home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1999 February: Tool Chest / Dev.CD Feb 99 TC.toast / What's New? / Development Kits / Mac OS USB v1.1f3 DDK / Examples / PrinterClassDriver / PrinterClassDriver.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-02  |  97.2 KB  |  3,005 lines  |  [TEXT/MPS ]

  1. /*
  2.     File:        PrinterClassDriver.c
  3.  
  4.     Contains:    MacOS USB printer class driver
  5.                 [ref. IEEE Std 1284-1994]
  6.  
  7.     Version:    xxx put version here xxx
  8.  
  9.     Copyright:    1998 by Apple Computer, Inc., all rights reserved.
  10.  
  11. */
  12.  
  13.  
  14. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  15.     includes
  16.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  17. #include <Devices.h>
  18. #include <DriverServices.h>
  19. #include <Interrupts.h>
  20. #include <LowMem.h>
  21. #include <Folders.h>
  22. #include <String.h>
  23. #include <stdio.h>
  24. #include <USB.h>
  25.  
  26. #ifndef __CODEFRAGMENTS__
  27. #include <codefragments.h>
  28. #endif
  29.  
  30. #include "PrinterClassDriver.h"
  31. #include "TradDriverLoaderLib.h"
  32.  
  33. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  34.     constants
  35.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  36. #define MAX_SUFFIX                    127        // maximum copies we'll enter in unit table
  37. #define kUSBParallelDrvrRsrcID    12
  38. #define kMinDrvrUnitNumber            48            // minimum unit table entry which we'll install
  39. #define kUSS720MillisecondDelay    3*1000    // poll every three seconds
  40. #define kUSS720StatusMSDelay        10            // poll one hundred times per second
  41. #define MAX_USB_TRANSFER_SIZE        TRANSFER_SIZE            // zero acts as manifest for conditional compilation
  42.  
  43. #define kUSBAttributeBulk            0x02
  44. #define kUSBInputEndpointMask        0x80
  45.  
  46. enum
  47. {
  48.     kCString = 0,                // StateStr, USBStatusStr selector
  49.     kPString,                    // StateStr, USBStatusStr selector
  50.     kDrvrFirstDigit = 5        // length_byte + ".USB" = 5
  51. };
  52. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  53.     manifest constants
  54. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  55. //
  56. //    DEBUGGING                        extra debugging information to USB Expert Log
  57. //    DOUBLE_BUFFER                    use a page aligned buffer in system heap to double buffer app i/o
  58. //    LOG                                echo all the write data to a log file in the system folder
  59. // LOCK_MEMORY                        LockMemory on the i/o buffer before write and unlock on write completion
  60. // VIRTUAL_MEMORY_CHECK            check the physical addresses of the buffer we pass for write requests
  61. // MACSBUG_ON_READ                break into MacsBug before each read request
  62. //    MACSBUG_ON_READ_COMPLETE    break into MacsBug at each read completion routine
  63. //    MACSBUG_ON_WRITE                break into MacsBug on each write request
  64. // MACSBUG_ON_WRITE_COMPLETE    break into MacsBug at each write completion routine
  65. //
  66. #define DEBUGGING                            0    /* DEBUGGING */
  67. #define DOUBLE_BUFFER                    1    /* DOUBLE_BUFFER */
  68. #define LOG                                    0    /* LOG */
  69. #define LOCK_MEMORY                        1    /* LOCK_MEMORY */
  70. #define MACSBUG_ON_READ                    0    /* MACSBUG_ON_READ */
  71. #define MACSBUG_ON_READ_COMPLETE        0    /* MACSBUG_ON_READ_COMPLETE */ 
  72. #define MACSBUG_ON_WRITE                0    /* MACSBUG_ON_WRITE */
  73. #define MACSBUG_ON_WRITE_COMPLETE    0    /* MACSBUG_ON_WRITE_COMPLETE */ 
  74. #define VIRTUAL_MEMORY_CHECK            0    /* VIRTUAL_MEMORY_CHECK require LOCK_MEMORY, currently broken */
  75.  
  76. #if LOG
  77. #define LOGGING(x)    x
  78. #include <stdio.h>
  79. #else
  80. #define LOGGING(x)
  81. #endif
  82.  
  83. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  84.     globals
  85.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  86. static struct usbPrinterPBStruct    printerClassRecord;
  87. static FSSpec                            printerClassDriverFileSpec;
  88. static NMRec                              gNMRec;
  89. LOGGING( static FILE                    *logfile );
  90. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  91.     prototypes
  92.   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  93.  
  94. static void    PrinterDeviceCompletionProc(USBPB *pb);
  95. static void SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb );
  96. static        USBEndPointDescriptor *FindEndpoint( USBInterfaceDescriptor *pInterface, int endpointType );
  97. static void    SoftReset( USBPB *usbprint, short interfaceNum );
  98. static void    CapabilityRequest( USBPB *pb, Ptr p, long length, short config, short interfaceNum, short alternateSetting );
  99. static void    CentronicsStatus( USBPB *usbprint, Ptr p, short interfaceNum );
  100. static void CompletionProc(USBPB *pb);
  101. static int    cstrlen( char *p );
  102. static void    cstrcpy( char *dst, char *src );
  103. static void    cstrcat( char *dst, char *src );
  104.  
  105. void            PrinterDeviceInitiateTransaction(USBPB *pb);
  106. void             CompleteDriverInit(NMRecPtr nmrecptr);
  107.  
  108. OSErr            CFMInitialization( CFragInitBlock *initBlock );
  109.  
  110. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  111.     Name:        HexString8
  112.  
  113.     Input Parameters:    
  114.         v                unsigned long value
  115.         
  116.     Output Parameters:
  117.         p                8 bytes: hex string representing value
  118.         
  119.     Description:
  120.  
  121.     Change History:
  122.         28 Feb 1998,    oja:        Original version.
  123. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  124. static void
  125. HexString8( unsigned long v, unsigned char *p )
  126. {
  127.     int    shift;
  128.     
  129.     for ( shift = 32-4; shift >= 0; shift -= 4 )
  130.     {
  131.         char c = (v >> shift) & 0x0F;
  132.         *p++ = c + (c > 9? ('A'-10): '0');
  133.     }
  134. }
  135.  
  136. #if DEBUG
  137. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  138.     Name:        hexstr
  139.  
  140.     Input Parameters:    
  141.         count                number of bytes
  142.         p                    pointer to bytes
  143.         
  144.     Output Parameters:
  145.         q                    hex dump of data
  146.         
  147.     Description:
  148.  
  149.     Change History:
  150.         28 Jul 1998,    oja:        Original version.
  151. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  152. void
  153. hexstr( int count, char *p, char *q );
  154.  
  155. void
  156. hexstr( int count, char *p, char *q )
  157. {
  158.     char *s = p;
  159.     int i = count;
  160.     for ( ; count > 0; --count, ++p )
  161.     {
  162.         int hi, lo;
  163.         hi = (*p >> 4)& 0x0F;
  164.         lo = *p & 0x0F;
  165.         *q++ = '0';
  166.         *q++ = 'x';
  167.         *q++ = hi + (hi > 9? 'A' - 10: '0');
  168.         *q++ = lo + (lo > 9? 'A' - 10: '0');
  169.         *q++ = ' ';
  170.     }
  171.     for ( ; i > 0; --i, ++s )
  172.         *q++ = *s < ' ' || *s > 0x7E? '.': *s;
  173. }
  174. #endif
  175.  
  176. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  177.     Name:        cstrlen
  178.  
  179.     Input Parameters:    
  180.         p            pointer to c-string
  181.         
  182.     Output Parameters:
  183.         int        length of string
  184.  
  185.     Description:
  186.         A replacement for strlen, since we don't want to depend on the
  187.         c library (can cause vm double page faults)
  188.  
  189.     Change History:
  190.         17 Aug 1998,    oja:        Original version.
  191. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  192.  
  193. static int
  194. cstrlen( char *p )
  195. {
  196.     int result = 0;
  197.     
  198.     while ( *p++ != '\0' )
  199.         ++result;
  200.  
  201.     return result;
  202. }
  203.  
  204. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  205.     Name:        cstrcpy
  206.  
  207.     Input Parameters:    
  208.         src        pointer to source c-string
  209.         
  210.     Output Parameters:
  211.         dst        c-string copy of src string
  212.  
  213.     Description:
  214.         A replacement for strcpy, since we don't want to depend on the
  215.         c library (can cause vm double page faults)
  216.  
  217.     Change History:
  218.         17 Aug 1998,    oja:        Original version.
  219. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  220.  
  221. static void
  222. cstrcpy( char *dst, char *src )
  223. {
  224.     while ( (*dst++ = *src++) != 0 )
  225.         ;
  226. }
  227.  
  228. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  229.     Name:        cstrcat
  230.  
  231.     Input Parameters:    
  232.         src        pointer to source c-string
  233.         
  234.     Output Parameters:
  235.         dst        c-string copy of src string
  236.  
  237.     Description:
  238.         A replacement for strcpy, since we don't want to depend on the
  239.         c library (can cause vm double page faults)
  240.  
  241.     Change History:
  242.         17 Aug 1998,    oja:        Original version.
  243. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  244.  
  245. static void
  246. cstrcat( char *dst, char *src )
  247. {
  248.     dst += cstrlen( dst );        // skip to end of the existing string
  249.     while ( (*dst++ = *src++) != 0 )
  250.         ;
  251. }
  252.  
  253. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  254.     Name:        USBStatusStr
  255.  
  256.     Input Parameters:    
  257.         usbStatus            usb error code
  258.         kind                    kPString or kCString
  259.         
  260.     Output Parameters:
  261.         unsigned char *    description of error (c-string or p-string)
  262.  
  263.     Description:
  264.         a simple mapping of errors to human-readable form
  265.  
  266.     Change History:
  267.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  268.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  269.         28 Feb 1998,    oja:        Original version.
  270. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  271. static unsigned char *
  272. USBStatusStr( OSStatus usbStatus, int kind )
  273. {
  274.     unsigned char *p;
  275.  
  276.     switch ( usbStatus )
  277.     {
  278.         case    kUSBInternalErr:                    p = "\p" kStrPrinterClass "Internal error"; break;
  279.         case    kUSBUnknownDeviceErr:            p = "\p" kStrPrinterClass "Unknown device"; break;
  280.         case    kUSBUnknownPipeErr:                 p = "\p" kStrPrinterClass "Unknown pipe"; break;
  281.         case    kUSBTooManyPipesErr:                p = "\p" kStrPrinterClass "Too many pipes"; break;
  282.         case    kUSBIncorrectTypeErr:            p = "\p" kStrPrinterClass "Incorrect type"; break;
  283.         case    kUSBRqErr:                            p = "\p" kStrPrinterClass "Request error"; break;
  284.         case    kUSBUnknownRequestErr:            p = "\p" kStrPrinterClass "Unknown request"; break;
  285.         case    kUSBTooManyTransactionsErr:    p = "\p" kStrPrinterClass "Too many transactions"; break;
  286.         case    kUSBAlreadyOpenErr:                p = "\p" kStrPrinterClass "Already open"; break;
  287.         case    kUSBNoDeviceErr:                    p = "\p" kStrPrinterClass "No device"; break;
  288.         case    kUSBDeviceErr:                        p = "\p" kStrPrinterClass "Device error"; break;
  289.         case    kUSBOutOfMemoryErr:                p = "\p" kStrPrinterClass "Out of memory"; break;
  290.         case    kUSBNotFound:                        p = "\p" kStrPrinterClass "Not found"; break;
  291.         case    kUSBLinkErr:                        p = "\p" kStrPrinterClass "Link Err"; break;
  292.         case    kUSBCRCErr:                            p = "\p" kStrPrinterClass "Comms/Device err, bad CRC";  break;        
  293.         case    kUSBBitstufErr:                    p = "\p" kStrPrinterClass "Comms/Device err, bitstuffing"; break;        
  294.         case    kUSBDataToggleErr:                p = "\p" kStrPrinterClass "Comms/Device err, Bad data toggle"; break;        
  295.         case    kUSBEndpointStallErr:            p = "\p" kStrPrinterClass "Device didn't understand"; break;        
  296.         case    kUSBNotRespondingErr:            p = "\p" kStrPrinterClass "No device, device hung"; break;        
  297.         case    kUSBPIDCheckErr:                    p = "\p" kStrPrinterClass "Comms/Device err, PID CRC error"; break;        
  298.         case    kUSBWrongPIDErr:                    p = "\p" kStrPrinterClass "Comms/Device err, Bad or wrong PID"; break;        
  299.         case    kUSBOverRunErr:                    p = "\p" kStrPrinterClass "Packet too large or more data than buffer"; break;        
  300.         case    kUSBUnderRunErr:                    p = "\p" kStrPrinterClass "Less data than buffer"; break;        
  301.         case    kUSBRes1Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  302.         case    kUSBRes2Err:                        p = "\p" kStrPrinterClass "kUSBRes1Err"; break;        
  303.         case    kUSBBufOvrRunErr:                    p = "\p" kStrPrinterClass "Buffer over run error"; break;        
  304.         case    kUSBBufUnderRunErr:                p = "\p" kStrPrinterClass "Buffer under run error"; break;        
  305.         case    kUSBNotSent1Err:                    p = "\p" kStrPrinterClass "Transaction not sent1"; break;        
  306.         case    kUSBNotSent2Err:                    p = "\p" kStrPrinterClass "Transaction not sent2"; break;    
  307.         default:
  308.             p = "\p" kStrPrinterClass "Unknown error nnnnnnnn";
  309.             HexString8( usbStatus, p + *p - 8 + 1 );
  310.             break;
  311.     }
  312.     
  313.     return kind == kPString? p: p + 1;
  314. }
  315.  
  316. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  317.     Name:        StateStr
  318.  
  319.     Input Parameters:    
  320.         usbRefCon            usb error code
  321.         kind                    kPString or kCString
  322.         
  323.     Output Parameters:
  324.         unsigned char *    description of state (c-string or p-string)
  325.  
  326.     Description:
  327.         a simple mapping of states to human-readable form
  328.  
  329.     Change History:
  330.         24 Apr 1998,    oja:        param to HexString8 was off-by-one
  331.         26 Mar 1998,    oja:        added kStrPrintClass to catenated strings
  332.         28 Feb 1998,    oja:        Original version.
  333. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  334. static unsigned char *
  335. StateStr( OSStatus refCon, int kind )
  336. {
  337.     unsigned char *p;
  338.  
  339.     refCon &= ~(kTransactionPending | kRetryTransaction | kAsyncTransaction | kReturnFromDriver);
  340.     switch ( refCon )
  341.     {
  342.         case kGetConfigurationDescriptor:        p = "\p" kStrPrinterClass "kGetConfigurationDescriptor"; break;
  343.         case kGetFullConfiguration:                p = "\p" kStrPrinterClass "kGetFullConfiguration"; break;
  344.         case kSetInterface:                            p = "\p" kStrPrinterClass "kSetInterface"; break;
  345.         case kGetCapabilityString:                    p = "\p" kStrPrinterClass "kGetCapabilityString"; break;
  346.         case kDelayGetCapability:                    p = "\p" kStrPrinterClass "kDelayGetCapability"; break;
  347.         case kGetFullCapabilityString:            p = "\p" kStrPrinterClass "kGetFullCapabilityString"; break;
  348.         case kGetInterface:                            p = "\p" kStrPrinterClass "kGetInterface"; break;
  349.         case kOpenBulkOutPipe:                        p = "\p" kStrPrinterClass "kOpenBulkOutPipe"; break;
  350.         case kOpenBulkInPipe:                        p = "\p" kStrPrinterClass "kOpenBulkInPipe"; break;
  351.         case kEnterNameRegistry:                    p = "\p" kStrPrinterClass "kEnterNameRegistry"; break;
  352.         default:
  353.             p = "\p" kStrPrinterClass "Unknown state nnnnnnnn";
  354.             HexString8( refCon, p + *p - 8 + 1 );
  355.             break;
  356.     }
  357.     return kind == kPString? p: p + 1;    
  358. }
  359.  
  360. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  361.     Name:        HiHex
  362.  
  363.     Input Parameters:    
  364.         v                        only low byte used
  365.         
  366.     Output Parameters:
  367.         <function result>    high nibble represented as ASCII char
  368.         
  369.     Description:
  370.  
  371.     Change History:
  372.         20 Mar 1998,    oja:        Original version.
  373. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  374. static unsigned char
  375. HiHex( int v )
  376. {
  377.     unsigned char    hinibble = (v >> 4) & 0x0f;
  378.     return hinibble + ((hinibble > 9)? ('A'-10): '0');
  379. }
  380.  
  381. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  382.     Name:        LoHex
  383.  
  384.     Input Parameters:    
  385.         v                        only low byte used
  386.         
  387.     Output Parameters:
  388.         <function result>    low nibble represented as ASCII char
  389.         
  390.     Description:
  391.  
  392.     Change History:
  393.         20 Mar 1998,    oja:        Original version.
  394. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  395. static unsigned char
  396. LoHex( int v )
  397. {
  398.     unsigned char    lonibble = v & 0x0f;
  399.     return lonibble + ((lonibble > 9)? ('A'-10): '0');
  400. }
  401.  
  402. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  403.     Name:        immediateError
  404.  
  405.     Input Parameters:    
  406.         
  407.     Output Parameters:
  408.         
  409.     Description:
  410.  
  411.     Change History:
  412.         28 Feb 1998,    oja:        Original version.
  413. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  414. static Boolean
  415. immediateError(OSStatus err)
  416. {
  417.     return((err != kUSBPending) && (err != noErr) );
  418. }
  419.  
  420. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  421.     Name:        SetNullUSBParamBlock
  422.  
  423.     Input Parameters:    
  424.         pb                    pointer to USB parameter block
  425.         dev                USB device reference
  426.     Output Parameters:
  427.         pb                    all fields set to default values
  428.  
  429.     Description:
  430.         setup a USB parameter block for use by the current device
  431.  
  432.     Change History:
  433.          8 Jun 1998,    oja:        modified for new param blocks
  434.         28 Feb 1998,    oja:        Original version.
  435. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  436. static void
  437. SetNullUSBParamBlock( USBDeviceRef dev, USBPB *pb )
  438. {
  439.     pb->qlink = NULL;
  440.     pb->qType = 0;
  441.     pb->pbLength = sizeof(USBPB);
  442.     pb->pbVersion = kUSBCurrentPBVersion;
  443.     pb->usbFlags = 0;
  444.     pb->usbStatus = noErr;
  445.     pb->usbCompletion = (USBCompletion) NULL;
  446.  
  447.     pb->usbReference = dev;
  448. }
  449.  
  450.  
  451. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  452.     Name:        CountInterface
  453.  
  454.     Input Parameters:    
  455.         pConfigDesc            pointer to USB device configuration string
  456.         intClass                USB class id
  457.         intSubClass            USB subclass id
  458.     
  459.     Output Parameters:
  460.         <function result>    number of interfaces which match the criteria
  461.     
  462.     Description:
  463.         Count the number of interfaces (and alternates) which match the
  464.         desired class and subclass.
  465.  
  466.     Change History:
  467.         26 Mar 1998,    oja:        use USBToHostWord to access length of
  468.                                         Configuration Descriptor
  469.         28 Feb 1998,    oja:        Original version.
  470. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  471. static int
  472. CountInterface(
  473.     USBConfigurationDescriptorPtr pConfigDesc,
  474.     int intClass,
  475.     int intSubClass
  476. )
  477. {
  478.     //
  479.     //    find an interface (and alternateSetting) which allows the desired class, subclass and protocol
  480.     //
  481.     int                                numInterfaces;
  482.     UInt32                            totalLength;
  483.     void                                *pEndOfDescriptors;
  484.     USBInterfaceDescriptorPtr    pMyIntDesc;
  485.     USBDescriptorHeaderPtr        pCurrentDesc;
  486.     Ptr                                p;
  487.     
  488.     totalLength = USBToHostWord( ((USBConfigurationDescriptorPtr)pConfigDesc)->totalLength );
  489.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  490.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  491.     
  492.     numInterfaces = 0;
  493.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  494.     {
  495.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  496.         {
  497.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  498.             if (pMyIntDesc->interfaceClass == intClass &&
  499.                     pMyIntDesc->interfaceSubClass == intSubClass )        // see if it's the request descriptor
  500.             {
  501.                 ++numInterfaces;
  502.             }
  503.         }
  504.         if ( pCurrentDesc->length == 0 )
  505.         {
  506.             IF_DEBUG( DebugStr( "\pCountInterfaces NULL" ) );
  507.             break;
  508.         }
  509.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;
  510.         pCurrentDesc = (USBDescriptorHeaderPtr) p;                    // Nope, that either wasn't an interface descriptor
  511.     }                                                            // or it was, but not the droid we're looking for.
  512.     return numInterfaces;
  513. }
  514.  
  515.  
  516. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  517.     Name:        FindInterface
  518.  
  519.     Input Parameters:
  520.         pPrinterPB
  521.         protocol                                (USB specification) protocol constant
  522.         
  523.     Output Parameters:
  524.         pPrinterPB->pb.usbBuffer        pointer to the interface
  525.         pPrinterPB->pb.usbReqCount        offset to the interface
  526.  
  527.     Description:
  528.         Synchronous.
  529.  
  530.         find a print interface (and alternateSetting) which allows 
  531.         the desired protocol
  532.         
  533.         Note although USBFindNextInterfaceDescriptor returns immediately
  534.         it still requires a completion routine.
  535.  
  536.     Change History:
  537.         28 Feb 1998,    oja:        Original version.
  538. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  539. static struct USBInterfaceDescriptor *
  540. FindInterface( USBConfigurationDescriptorPtr pConfigDesc, int protocol )
  541. {
  542.     //
  543.     //    find a print interface (and alternateSetting) which allows 
  544.     //        the desired protocol
  545.     //
  546.     //
  547.     int                                numInterfaces;
  548.     UInt32                            totalLength;
  549.     void                                *pEndOfDescriptors;
  550.     USBInterfaceDescriptorPtr    pMyIntDesc;
  551.     USBDescriptorHeaderPtr        pCurrentDesc;
  552.     Ptr                                p;
  553.     
  554.     totalLength = USBToHostWord( pConfigDesc->totalLength );
  555.     pEndOfDescriptors = (Ptr)pConfigDesc + totalLength;                // get the total length and add it to the start of the config space
  556.     pCurrentDesc = (USBDescriptorHeaderPtr)pConfigDesc;                // point the currentdesc to the start of the config space
  557.     
  558.     numInterfaces = 0;
  559.     while (pCurrentDesc < pEndOfDescriptors)                        // as long as we haven't exhausted all the descriptors
  560.     {
  561.         if (pCurrentDesc->descriptorType == kUSBInterfaceDesc)    // look at the current descriptor
  562.         {
  563.             pMyIntDesc = (USBInterfaceDescriptorPtr)pCurrentDesc;    // if it's an interface descriptor
  564.             if (pMyIntDesc->interfaceClass == kUSBPrintClass &&
  565.                     pMyIntDesc->interfaceSubClass == kUSBPrintSubClass &&
  566.                     pMyIntDesc->interfaceProtocol == protocol    )        // see if it's the requested descriptor
  567.                 break;
  568.         }
  569.         if ( pCurrentDesc->length == 0 )
  570.         {
  571.             IF_DEBUG( DebugStr( "\pFindInterface NULL" ) );
  572.             pCurrentDesc = pEndOfDescriptors;    // shouldn't happen
  573.             break;
  574.         }
  575.         p = (Ptr)pCurrentDesc + pCurrentDesc->length;                    // Nope, that either wasn't an interface descriptor
  576.         pCurrentDesc = (USBDescriptorHeaderPtr) p;
  577.     }                                                            // or it was, but not the droid we're looking for.
  578.     return pCurrentDesc < pEndOfDescriptors? (struct USBInterfaceDescriptor *) pCurrentDesc: NULL;
  579.  
  580. }
  581.  
  582. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  583.     Name:        FindEndpoint
  584.  
  585.     Input Parameters:    
  586.         pInterface            pointer to interface descriptor
  587.         kind                    kUSBIn, kUSBOut
  588.         
  589.     Output Parameters:
  590.         result                pointer to bulk endpoint descriptor
  591.     
  592.     Description:
  593.  
  594.     Change History:
  595.          8 Jun 1998,    oja:        Original version.
  596. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  597.  
  598. static USBEndPointDescriptor *
  599. FindEndpoint( USBInterfaceDescriptor *pInterface, int kind )
  600. {
  601.     USBEndPointDescriptor    *pEndpoint = (USBEndPointDescriptor *) (pInterface->length + (Ptr) pInterface),
  602.                                     *pEndOfEndpoints = pEndpoint + pInterface->numEndpoints;
  603.  
  604.     UInt8                            addressMask = kind == kUSBIn? 0x80: 0;
  605.     while ( pEndpoint < pEndOfEndpoints )
  606.     {
  607.         Ptr    p = (Ptr) pEndpoint;
  608.         if ( pEndpoint->attributes == 2 && ((pEndpoint->endpointAddress & addressMask) == addressMask) )
  609.             break;
  610.         
  611.         p += pEndpoint->length;
  612.         pEndpoint = (USBEndPointDescriptor *) p;
  613.     }
  614.     
  615.     return pEndpoint < pEndOfEndpoints? pEndpoint: NULL;
  616. }
  617.  
  618. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  619.     Name:        ParseCapability
  620.  
  621.     Input Parameters:    
  622.         capability            pointer to 1284-1994 capability string
  623.         attribute            pointer to c-string key we're retrieving (terminate with colon)
  624.         *result_length        maximum length of the result 
  625.         
  626.     Output Parameters:
  627.         result                c-string which followed the key and was terminated by semi-colon
  628.                                 (semi-colon has been stripped)
  629.         *result_length        actual length of the result (may be zero)
  630.     
  631.     Description:
  632.         Search for "attribute" in the 1284 "capability" string
  633.         The identifier is terminated with a semi-colon
  634.  
  635.         Return the attribute in result
  636.             null-string if attribute not found.
  637.  
  638.     Change History:
  639.         20 Jul 1998,    oja:        fix computation of target_length
  640.         28 Feb 1998,    oja:        Original version.
  641. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  642. static void
  643. ParseCapability(
  644.     unsigned char    *capability,
  645.     unsigned char    *attribute,
  646.     unsigned char    *result,
  647.     int                *result_length 
  648. )
  649. {
  650.     //
  651.     //    search for "attribute" in the 1284 "capability" string
  652.     //
  653.     //    the identifier is terminated with a semi-colon
  654.     //
  655.     //    return the attribute in result
  656.     //            null-string if attribute not found
  657.     //
  658.     //    <to do> skip blanks, isolate colon, skip blanks
  659.     //
  660.     int                source_length,
  661.                         target_length;
  662.     unsigned char    *source,
  663.                         *target,
  664.                         *destination;
  665.     //
  666.     //    begin a brute force search
  667.     //
  668.     source = attribute;
  669.     source_length = cstrlen((char *)attribute );
  670.  
  671.     target = capability + 2;    // skip the length
  672.     target_length =  capability[1] | (capability[0] << 8);
  673.     target_length -= 2;            // don't count the length
  674.     while ( target_length >= source_length )
  675.     {
  676.         if ( memcmp( source, target, source_length ) == 0 )
  677.             break;
  678.         --target_length;
  679.         ++target;
  680.     }
  681.  
  682.     destination = result;
  683.     *destination = 0;    // empty result
  684.  
  685.     target += source_length;
  686.     target_length -= source_length;    // skip the attribute string
  687.  
  688.     if ( target_length > 0 )
  689.     {
  690.         //
  691.         //    we found the attribute in the capability string
  692.         //
  693.         while ( destination - result < *result_length )    // arbitrarily limit reply
  694.         {
  695.             if ( *target == ';' )
  696.                 break;
  697.             *destination++ = *target++;        // copy a byte of attribute over
  698.         }
  699.         *destination++ = '\0';                        // trailing NUL
  700.         *result_length = destination - result;    // report the length of the data (with trailing NUL)
  701.     }
  702. }
  703.  
  704.  
  705. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  706.     Name:        GetClass
  707.  
  708.     Input Parameters:    
  709.         capability            pointer to 1284-1994 capability string
  710.         *result_length        maximum length of the result 
  711.         
  712.     Output Parameters:
  713.         result                c-string extracted from the MODEL key
  714.         *result_length        actual length of the result  (may be zero)
  715.         
  716.     Description:
  717.         CLASS is a Microsoft extension to the 1284-capability string
  718.         if we don't find it
  719.             we assume that the device is a printer
  720.         Since the USB hardware has already indicated this, we're really allowing
  721.         devices which aren't printers to be reached via the DRVRs we've installed.
  722.  
  723.     Change History:
  724.         26 Mar 1998,    oja:        result_length is output too
  725.         28 Feb 1998,    oja:        Original version.
  726. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  727. static void
  728. GetClass(
  729.     unsigned char    *capability,
  730.     unsigned char    *result,
  731.     int                *result_length
  732. )
  733. {
  734.     //
  735.     //    We supply the upper-case PRINTER to be consistent with 1284-1994
  736.     //        if we don't find a class.
  737.     //
  738.     ParseCapability( capability, (unsigned char *) "CLASS:", result, result_length);
  739.     if ( *result == '\0' )
  740.         ParseCapability( capability, (unsigned char *) "CLS:", result, result_length);
  741.     if ( *result == '\0' )
  742.         cstrcpy( (char *)result, "PRINTER" );
  743. }
  744.  
  745.  
  746. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  747.     Name:        GetModel
  748.  
  749.     Input Parameters:    
  750.         capability            pointer to 1284-1994 capability string
  751.         *result_length        maximum length of the result 
  752.         
  753.     Output Parameters:
  754.         result                c-string extracted from the MODEL key
  755.         *result_length        actual length of the result  (may be zero)
  756.             
  757.     Description:
  758.         MODEL is a required field of the 1284-capability string
  759.         MODEL may be abbreviated MDL
  760.  
  761.     Change History:
  762.         26 Mar 1998,    oja:        result_length is output too
  763.         28 Feb 1998,    oja:        Original version.
  764. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  765. static void
  766. GetModel(
  767.     unsigned char    *capability, 
  768.     unsigned char    *result,
  769.     int                *result_length
  770. )
  771. {
  772.     //
  773.     //    Most manufacturers abbreviate, so we search for MDL first
  774.     //
  775.     ParseCapability( capability, (unsigned char *) "MDL:", result, result_length );
  776.     if ( *result == '\0' )
  777.         ParseCapability( capability, (unsigned char *) "MODEL:", result, result_length );
  778. }
  779.  
  780.  
  781. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  782.     Name:        GetCommandSet
  783.  
  784.     Input Parameters:    
  785.         
  786.     Output Parameters:
  787.         
  788.     Description:
  789.  
  790.     Change History:
  791.         11 Nov 1998,    oja:        look for COMMAND SET not COMMAND-SET
  792.         28 Feb 1998,    oja:        Original version.
  793. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  794. static void
  795. GetCommandSet(
  796.     unsigned char *capability, 
  797.     unsigned char *result,
  798.     int *result_length
  799. )
  800. {
  801.     //
  802.     //    COMMAND-SET is a required field of the 1284-capability string
  803.     //    COMMAND-SET may be abbreviated CMD
  804.     //
  805.     ParseCapability( capability, (unsigned char *) "CMD:", result, result_length );
  806.     if ( *result == '\0' )
  807.         ParseCapability( capability, (unsigned char *) "COMMAND SET:", result, result_length );
  808. }
  809.  
  810. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  811.     Name:        GetManufacturer
  812.  
  813.     Input Parameters:    
  814.         
  815.     Output Parameters:
  816.         
  817.     Description:
  818.  
  819.     Change History:
  820.         26 Jun 1998,    oja:        Original version.
  821. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  822. static void
  823. GetManufacturer(
  824.     unsigned char *capability, 
  825.     unsigned char *result,
  826.     int *result_length
  827. )
  828. {
  829.     //
  830.     //    MANUFACTURER is a required field of the 1284-capability string
  831.     //    MANUFACTURER may be abbreviated MFG
  832.     //
  833.     ParseCapability( capability, (unsigned char *) "MFG:", result, result_length );
  834.     if ( *result == '\0' )
  835.         ParseCapability( capability, (unsigned char *) "MANUFACTURER:", result, result_length );
  836. }
  837.  
  838. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  839.     Name:        OpenBulkEndpoint
  840.  
  841.     Input Parameters:    
  842.         pPrinterPB
  843.         refCon
  844.  
  845.     Output Parameters:
  846.         pb->usbReference    on (asynchronous) completion
  847.         
  848.     Description:
  849.         Asynchronous completion.
  850.  
  851.         Open a bulkIn or bulkOut endpoint
  852.  
  853.     Change History:
  854.         21 Jul 1998,    oja:        call SetNullParamBlock
  855.         28 Feb 1998,    oja:        Original version.
  856. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  857. OSStatus
  858. OpenBulkEndpoint(
  859.     struct usbPrinterPBStruct    *pPrinterPB,
  860.     UInt32                            refCon
  861. )
  862. {
  863.  
  864.     OSStatus                        err;
  865.     USBEndPointDescriptor    *eDesc;
  866.     USBPB                            *pb = &pPrinterPB->pb;
  867.     //
  868.     // The params are set up correctly so open it
  869.     //    asynchronous completion will set usbReference to a pipe
  870.     //
  871.     SetNullUSBParamBlock(pPrinterPB->device,  pb );
  872.     switch (refCon)
  873.     {
  874.     case kOpenBulkOutPipe:
  875.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBOut );
  876.         pPrinterPB->writeDescriptor = eDesc;
  877.         pb->usbFlags = kUSBOut;
  878.         break;
  879.     case kOpenBulkInPipe:
  880.         eDesc = FindEndpoint( pPrinterPB->interface, kUSBIn );
  881.         pPrinterPB->readDescriptor = eDesc;
  882.         pb->usbFlags = kUSBIn;
  883.         break;
  884.     default:
  885.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "OpenEndpoint undefined refCon",1);
  886.         break;
  887.     }
  888.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  889.  
  890.     pb->pbVersion = kUSBCurrentPBVersion;
  891.     pb->usbClassType = kUSBBulk;
  892.     pb->usbOther = eDesc->endpointAddress & ~0x80;
  893.     pb->usb.cntl.WValue = USBToHostWord(eDesc->maxPacketSize);
  894.     pb->usbRefcon = refCon | kTransactionPending | kAsyncTransaction;
  895.  
  896.     err = USBOpenPipe( pb );
  897.     if(immediateError(err))
  898.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "OpenEndpoint Failed Open pipe", 0);
  899.  
  900.     return err;
  901. }
  902.  
  903. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  904.     Name:        DeregisterDevice
  905.  
  906.     Input Parameters:    
  907.         pPrinterPB
  908.  
  909.     Output Parameters:
  910.         <none>
  911.         
  912.     Description:
  913.         remove the device from the name registry
  914.  
  915.     Change History:
  916.         11 Jun 1998,    oja:        test from RegistryCStrEntryLookup was wrong direction
  917.         17 Apr 1998,    oja:        Original version.
  918. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  919. static OSStatus
  920. DeregisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  921. {
  922.     OSStatus        err;
  923.     RegEntryID    self;
  924.  
  925.     RegistryEntryIDInit( &self );
  926.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  927.     if ( err == noErr )
  928.     {
  929.         err = RegistryEntryDelete( &self);
  930.     }
  931.     RegistryEntryIDDispose(&self);
  932.     if (err == noErr &&  pPrinterPB->outRefNum != -1 )
  933.         err = TradRemoveDriver( pPrinterPB->outRefNum, false );
  934.     if (err == noErr &&  pPrinterPB->inRefNum != -1 )
  935.         err = TradRemoveDriver( pPrinterPB->inRefNum, false );
  936.     
  937.     return err;
  938. }
  939.  
  940. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  941.     Name:        RegisterDevice
  942.  
  943.     Input Parameters:    
  944.         pPrinterPB
  945.  
  946.     Output Parameters:
  947.         <none>
  948.         
  949.     Description:
  950.         add the device into the name registry; we can't insert just the node
  951.         if the parent nodes aren't present.
  952.  
  953.         if it isn't present
  954.             insert the device CLASS into the registry
  955.         if it isn't present
  956.             insert the device MODEL into the registry
  957.         finally insert the device itself into the registry
  958.             we're careful to rename multiple devices
  959.  
  960.     Change History:
  961.         16 Nov 1998,    oja:        better support for attributes which aren't in string
  962.         16 Jul 1998,    oja:        fix params to sprintf
  963.          8 Jun 1998,    oja:        don't use register param (CW build)
  964.         26 Mar 1998,    oja:        only register significant part of drvrNames 
  965.                                         log null model name to Expert
  966.                                         register command set 
  967.         28 Feb 1998,    oja:        Original version.
  968. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  969. static OSStatus
  970. RegisterDevice( struct usbPrinterPBStruct *pPrinterPB )
  971. {
  972.     //
  973.     //    add the device into the name registry
  974.     //    if it isn't present
  975.     //        insert the device CLASS into the registry
  976.     //    if it isn't present
  977.     //        insert the device MODEL into the registry
  978.     //    finally insert the device itself into the registry
  979.     //        we're careful to rename multiple devices
  980.     //
  981.     Str255        identification,
  982.                     devclass,
  983.                     model,
  984.                     commands;
  985.     RegEntryID    parent, where, self;
  986.     OSStatus        err;
  987.     int            model_length,
  988.                     command_length,
  989.                     class_length;
  990.  
  991.     class_length = sizeof(devclass);
  992.     GetClass( pPrinterPB->capabilityString, devclass, &class_length );
  993.  
  994.     command_length = sizeof(commands);
  995.     GetCommandSet(pPrinterPB->capabilityString, commands, &command_length );
  996.  
  997.     cstrcpy( (char *)pPrinterPB->name, (char *)"Devices:device-tree:" );
  998.     cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  999.     
  1000.     RegistryEntryIDInit( &where );
  1001.     err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name, &where );
  1002.     if ( err == nrPathNotFound ) 
  1003.     {
  1004.         //    class not in registry
  1005.         //        create a node for all devices of this CLASS
  1006.         //
  1007.         RegistryEntryIDInit( &parent );
  1008.         err = RegistryCStrEntryLookup( nil, "Devices:device-tree:" , &parent );
  1009.         if ( err == noErr )
  1010.             err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &where );
  1011.         RegistryEntryIDDispose(&parent);
  1012.  
  1013.     }
  1014.     //
  1015.     //    add this model into the name registry of this class
  1016.     //
  1017.     if ( err == noErr )
  1018.     {
  1019.         model_length = sizeof(model);
  1020.         GetModel( pPrinterPB->capabilityString, model, &model_length );
  1021.         if ( *model != '\0' )
  1022.         {
  1023.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  1024.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  1025.             cstrcat( (char *)pPrinterPB->name, ":" );
  1026.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  1027.             RegistryEntryIDInit( &self );
  1028.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  1029.             if ( err != noErr )
  1030.             {
  1031.                 // model not in registry
  1032.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  1033.             }
  1034.             RegistryEntryIDDispose(&self);
  1035.         }
  1036.     }
  1037.     //
  1038.     //    add this instance of this model of this class
  1039.     //        into the name registry
  1040.     //
  1041.     if ( *model == '\0'  )
  1042.     {
  1043.         //
  1044.         //    possibly the cable isn't firmly connected or the printer isn't switched on
  1045.         //
  1046.         err = kUSBInternalErr;
  1047.         USBExpertFatalError(pPrinterPB->device, err, kStrPrinterClass "\pModel undefined", 0);
  1048.     }
  1049.     if ( err == noErr )
  1050.     {
  1051.         //
  1052.         //    start off by identifying the device simply by the model name
  1053.         //        increment the numeric suffix until we successfully registry the device
  1054.         //
  1055.         Str32    suffix;
  1056.         int    numeric_suffix;
  1057.  
  1058.         cstrcpy( (char *)identification, (char *)model );
  1059.         RegistryEntryIDInit( &self );
  1060.         for ( numeric_suffix = 1; numeric_suffix < MAX_SUFFIX; ++numeric_suffix )
  1061.         {
  1062.             cstrcpy( (char *)pPrinterPB->name, "Devices:device-tree:" );
  1063.             cstrcat( (char *)pPrinterPB->name, (char *)devclass );
  1064.             cstrcat( (char *)pPrinterPB->name, ":" );
  1065.             cstrcat( (char *)pPrinterPB->name, (char *)model );
  1066.             cstrcat( (char *)pPrinterPB->name, ":" );
  1067.             cstrcat( (char *)pPrinterPB->name, (char *)identification );
  1068.             err = RegistryCStrEntryLookup( nil, (char const *) pPrinterPB->name , &self );
  1069.             if ( err != noErr )
  1070.             {
  1071.                 // enter device in registry
  1072.                 err = RegistryCStrEntryCreate( nil, (char const *) pPrinterPB->name, &self );
  1073.                 if ( err == noErr )
  1074.                     err = RegistryPropertyCreate( &self, "drvrOut", &pPrinterPB->driverOutName, 1 + pPrinterPB->driverOutName[0] );
  1075.                 if ( err == noErr )
  1076.                     err = RegistryPropertyCreate( &self, "outRef", &pPrinterPB->outRefNum, sizeof(pPrinterPB->outRefNum) );
  1077.                 if ( err == noErr )
  1078.                     err = RegistryPropertyCreate( &self, "drvrIn", &pPrinterPB->driverInName, 1 + pPrinterPB->driverInName[0] );
  1079.                 if ( err == noErr )
  1080.                     err = RegistryPropertyCreate( &self, "inRef", &pPrinterPB->inRefNum, sizeof(pPrinterPB->inRefNum) );
  1081.                 if ( err == noErr )
  1082.                     err = RegistryPropertyCreate( &self, "privateData", &pPrinterPB, sizeof(pPrinterPB) );
  1083.                 if ( err == noErr )
  1084.                     err = RegistryPropertyCreate( &self, "read", &pPrinterPB->r, sizeof(QueueUSBReadUPP) );
  1085.                 if ( err == noErr )
  1086.                     err = RegistryPropertyCreate( &self, "write", &pPrinterPB->w, sizeof(QueueUSBWriteUPP) );
  1087.                 if ( err == noErr && *commands != '\0' )
  1088.                     err = RegistryPropertyCreate( &self, "command-set", &commands, command_length );
  1089.                 break;
  1090.             }
  1091.             //
  1092.             //    if this name didn't succeed
  1093.             //        try the next numeric suffix
  1094.             //
  1095.             sprintf( (char *)suffix, " %d", numeric_suffix );
  1096.             cstrcpy( (char *)identification, (char *)model );
  1097.             cstrcat( (char *)identification, (char *)suffix );
  1098.         }
  1099.         RegistryEntryIDDispose(&self);
  1100.     }
  1101.     USBExpertStatus( pPrinterPB->device, pPrinterPB->name, err );
  1102.     RegistryEntryIDDispose(&where);
  1103.  
  1104.     LOGGING( logfile = fopen( "USBPrinter.log", "wb+" ) );
  1105.     return err;
  1106. }
  1107.  
  1108. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1109.     Name:        LoadResources
  1110.  
  1111.     Input Parameters:
  1112.         pPrinterPB            pointer to class driver's private storage
  1113.         
  1114.     Output Parameters:
  1115.         OSStatus                resource load error
  1116.         
  1117.     Description:
  1118.         Initialize time is the only safe time to to load resources from our file.
  1119.         Here's where we load resources and detach them from the resource manager.
  1120.         Later we'll use these private copies instead of GetResource calls.
  1121.         
  1122.         Using the file spec that we got from the CFMInitialization routine, open
  1123.         our resource fork.
  1124.  
  1125.     Change History:
  1126.         11 Jun 1998,    oja:        removed hardcoded filename, use printerClassDriverFileSpec
  1127.         20 Mar 1998,    oja:        Original version.
  1128. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1129. static OSStatus
  1130. LoadResources( struct usbPrinterPBStruct *pPrinterPB )
  1131. {
  1132.     short            rf = -1;                // class driver resource fork
  1133.     OSStatus        err;
  1134.  
  1135.     //
  1136.     //    open the resource fork of this class driver
  1137.     //
  1138.     rf = FSpOpenResFile( &printerClassDriverFileSpec,fsRdPerm );
  1139.     err = ResError();
  1140.     
  1141.     //
  1142.     //    load the DRVR that we'll stick in the unit table
  1143.     //
  1144.     pPrinterPB->hDrvr = NULL;
  1145.     if ( err == noErr )
  1146.     {
  1147.         pPrinterPB->hDrvr = (DRVRHeaderHandle) Get1Resource( 'DRVR',  kUSBParallelDrvrRsrcID );
  1148.         if ( pPrinterPB->hDrvr != NULL )
  1149.             DetachResource( (Handle) pPrinterPB->hDrvr );
  1150.         err = ResError();
  1151.     }
  1152.     
  1153.     if ( rf != -1 )
  1154.         CloseResFile( rf );
  1155.     
  1156.     return err;
  1157. }
  1158.  
  1159. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1160.     Name:        InstallDrivers
  1161.  
  1162.     Input Parameters:
  1163.         pPrinterPB
  1164.         
  1165.     Output Parameters:
  1166.         OSStatus            error code
  1167.         
  1168.     Description:
  1169.         install read and write drivers in the unit table
  1170.             we have separate drivers so that we can support a full-duplex protocol
  1171.         rename the driver we just installed (so multiple copies don't conflict)
  1172.         We use the DRVR -refnum-1 so that the driver name has the same hex chars
  1173.             as the driver number (for manual verification in MacsBug)
  1174.  
  1175.     Change History:
  1176.         13 Jul 1998,    oja:        init err to noErr
  1177.         26 Mar 1998,    oja:        Use refnum -1, use infix location to enumerate
  1178.                                         DRVR
  1179.         28 Feb 1998,    oja:        Original version.
  1180. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1181. static OSStatus
  1182. InstallDrivers( struct usbPrinterPBStruct *pPrinterPB )
  1183. {
  1184.     //
  1185.     //    install the driver in the unit table
  1186.     //    rename the driver we just installed (so multiple copies don't conflict)
  1187.     //    
  1188.     short            refNum;                // DRVR refNum
  1189.     OSStatus        err =  paramErr;    // couldn't find driver
  1190.  
  1191.     if ( pPrinterPB->hDrvr != NULL )
  1192.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->outRefNum );
  1193.  
  1194.     if ( err == noErr )
  1195.     {
  1196.         UnitNumber        unit;
  1197.         DriverFlags        flags;
  1198.         DRVRHeaderPtr    hdr;
  1199.         unsigned char    *suffix,        // append "In" and "Out"
  1200.                             *infix;        // driver reference number follows the ".USB"
  1201.  
  1202.         TradGetDriverInformation( pPrinterPB->outRefNum, &unit, &flags, pPrinterPB->driverOutName, &hdr );
  1203.         BlockMove( pPrinterPB->driverOutName, pPrinterPB->driverInName, 1 + pPrinterPB->driverOutName[0] );
  1204.         
  1205.         suffix = pPrinterPB->driverOutName + pPrinterPB->driverOutName[0] - 2;
  1206.         infix = pPrinterPB->driverOutName + kDrvrFirstDigit;
  1207.         infix[0] = HiHex( -pPrinterPB->outRefNum -1 );
  1208.         infix[1] = LoHex( -pPrinterPB->outRefNum -1 );
  1209.         suffix[0] = 'O';
  1210.         suffix[1] = 'u';
  1211.         suffix[2] = 't';
  1212.         TradRenameDriver( pPrinterPB->outRefNum, pPrinterPB->driverOutName );
  1213.         //
  1214.         //    set the driver data to point to our parameter block
  1215.         //
  1216.         err = OpenDriver( pPrinterPB->driverOutName, &refNum );
  1217.         if ( err == noErr )
  1218.         {
  1219.             struct usbPrinterPBStruct *param = pPrinterPB;
  1220.             err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1221.             CloseDriver( refNum );
  1222.         }
  1223.         err = TradInstallDriverFromHandle( pPrinterPB->hDrvr, kMinDrvrUnitNumber, TradHighestUnitNumber() + 1, &pPrinterPB->inRefNum );
  1224.         if ( err == noErr )
  1225.         {
  1226.             
  1227.             suffix = pPrinterPB->driverInName + pPrinterPB->driverInName[0] - 1;
  1228.             infix = pPrinterPB->driverInName + kDrvrFirstDigit;
  1229.             infix[0] = HiHex( -pPrinterPB->inRefNum -1 );
  1230.             infix[1] = LoHex( -pPrinterPB->inRefNum -1 );
  1231.             suffix[0] = 'I';
  1232.             suffix[1] = 'n';
  1233.             TradRenameDriver( pPrinterPB->inRefNum, pPrinterPB->driverInName );
  1234.             //
  1235.             //    set the driver data to point to our parameter block
  1236.             //
  1237.             err = OpenDriver( pPrinterPB->driverInName, &refNum );
  1238.             if ( err == noErr )
  1239.             {
  1240.                 struct usbPrinterPBStruct *param = pPrinterPB;
  1241.                 err = Control( refNum, kDrvrPrivateSetStorage, ¶m );
  1242.                 CloseDriver( refNum );
  1243.             }
  1244.         }
  1245.     }
  1246.  
  1247.     return err;
  1248. }
  1249.  
  1250. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1251.     Name:        GetCapability
  1252.  
  1253.     Input Parameters:    
  1254.         
  1255.     Output Parameters:
  1256.         
  1257.     Description:
  1258.         Asynchronous completion.
  1259.  
  1260.     Change History:
  1261.         28 Feb 1998,    oja:        Original version.
  1262. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1263. static void
  1264. GetCapability( struct usbPrinterPBStruct *pPrinterPB, unsigned char *p, int length )
  1265. {
  1266.     //
  1267.     //    queue a transaction to retrieve the 1284 capability string
  1268.     //        we must have assigned the interface by this point since the capability string
  1269.     //        may vary with the interface
  1270.     //
  1271.     OSStatus        err;
  1272.     USBPB            *pb = &pPrinterPB->pb;
  1273.     
  1274.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  1275.  
  1276.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  1277.     pb->usb.cntl.WValue = (pPrinterPB->config)->configValue;        // configuration
  1278.     pb->usb.cntl.WIndex = ((pPrinterPB->interface)->interfaceNumber<<8) | (pPrinterPB->interface)->alternateSetting;
  1279.  
  1280.     pb->usbReqCount = length;
  1281.     pb->usbBuffer = p;
  1282.  
  1283.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1284.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1285.  
  1286.     err = USBDeviceRequest(pb);
  1287.     if(immediateError(err))
  1288.     {
  1289.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetCapability", 0);
  1290.     }
  1291. }
  1292.  
  1293. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1294.     Name:        IsLucentCable
  1295.  
  1296.     Input Parameters:    
  1297.         dev            USB device descriptor
  1298.         
  1299.     Output Parameters:
  1300.         Return 1 if the USB device is a USB-parallel cable
  1301.         
  1302.     Description:
  1303.         
  1304.  
  1305.     Change History:
  1306.         28 Feb 1998,    oja:        Original version.
  1307. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1308. static int
  1309. IsLucentCable( USBDeviceDescriptor    *dev )
  1310. {
  1311.     return ( USBToHostWord(dev->vendor) == 0x47E && USBToHostWord(dev->product) == 0x1001 )? 1: 0;
  1312. }
  1313.  
  1314.  
  1315. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1316.     Name:        SetInterface
  1317.  
  1318.     Input Parameters:    
  1319.         
  1320.     Output Parameters:
  1321.         
  1322.     Description:
  1323.         Asynchronous completion.
  1324.  
  1325.     Change History:
  1326.         28 Feb 1998,    oja:        Original version.
  1327. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1328. static void
  1329. SetInterface( USBPB *pb, int whichInterface, int whichAlternate )
  1330. {
  1331.     //
  1332.     //    the device has multiple printer interfaces
  1333.     //        select either the bi-directional or uni-directional interface
  1334.     OSStatus    err;
  1335.  
  1336.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBStandard, kUSBInterface);
  1337.  
  1338.     pb->usb.cntl.BRequest = kUSBRqSetInterface;
  1339.     pb->usb.cntl.WValue = whichAlternate;        // alternate setting
  1340.     pb->usb.cntl.WIndex = whichInterface;        // interface
  1341.  
  1342.     pb->usbReqCount = 0;
  1343.     pb->usbBuffer = NULL;
  1344.  
  1345.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1346.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1347.  
  1348.     err = USBDeviceRequest(pb);
  1349.     if(immediateError(err))
  1350.     {
  1351.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "SetInterface", 0);
  1352.     }
  1353. }
  1354.  
  1355. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1356.     Name:        GetInterface
  1357.  
  1358.     Input Parameters:    
  1359.         
  1360.     Output Parameters:
  1361.         
  1362.     Description:
  1363.         Asynchronous completion.
  1364.  
  1365.     Change History:
  1366.         28 Feb 1998,    oja:        Original version.
  1367. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1368. static void
  1369. GetInterface( USBPB *pb, UInt8 *alt )
  1370. {
  1371.     //
  1372.     //    make sure we account for any alternate interface currently in use by the device
  1373.     //
  1374.     OSStatus    err;
  1375.  
  1376.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBInterface);
  1377.  
  1378.     pb->usb.cntl.BRequest = kUSBRqGetInterface;
  1379.     pb->usb.cntl.WValue = 0; 
  1380.     pb->usb.cntl.WIndex = 0;
  1381.  
  1382.     pb->usbReqCount = sizeof(UInt8);        // single byte is requested
  1383.     pb->usbBuffer = alt;
  1384.  
  1385.     pb->usbStatus = 0;
  1386.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1387.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1388.  
  1389.     err = USBDeviceRequest(pb);
  1390.     if(immediateError(err))
  1391.     {
  1392.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetInterface", 0);
  1393.     }
  1394. }
  1395.  
  1396. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1397.     Name:        GetConfigurationDescriptor
  1398.  
  1399.     Input Parameters:    
  1400.         pb                        USB parameter block
  1401.         pConfiguration        storage for the reply
  1402.         length                number of bytes allocated for the reply
  1403.         
  1404.     Output Parameters:
  1405.         pConfiguration        the device's configuration descriptor (possibly truncated)
  1406.         
  1407.     Description:
  1408.         Asynchronous completion.
  1409.  
  1410.         Retrieve the device's configuration descriptor. Note that we may not get
  1411.         the full configuration--the client must read the length in the reply and
  1412.         determine if the call successfully completed retrieval of the full config-
  1413.         uration descriptor.
  1414.  
  1415.     Change History:
  1416.         28 Feb 1998,    oja:        Original version.
  1417. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1418. static void
  1419. GetConfigurationDescriptor(
  1420.     USBPB *pb,
  1421.     USBConfigurationDescriptorPtr pConfiguration, 
  1422.     int length
  1423. )
  1424. {
  1425.     OSStatus    err;
  1426.  
  1427.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBStandard, kUSBDevice);
  1428.  
  1429.     pb->usb.cntl.BRequest = kUSBRqGetDescriptor;
  1430.     pb->usb.cntl.WValue = (kUSBConfDesc<<8) + 0; 
  1431.     pb->usb.cntl.WIndex = 0;    //language
  1432.  
  1433.     pb->usbReqCount = length;
  1434.     pb->usbBuffer = pConfiguration;
  1435.  
  1436.     pb->usbStatus = 0;
  1437.     pb->usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  1438.     pb->usbRefcon |= kTransactionPending | kAsyncTransaction;
  1439.  
  1440.     err = USBDeviceRequest(pb);
  1441.     if(immediateError(err))
  1442.     {
  1443.         USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "GetConfigurationDescriptor", 0);
  1444.     }
  1445. }
  1446.  
  1447. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1448.     Name:        ReadCompletion
  1449.  
  1450.     Input Parameters:    
  1451.         pb                        USB parameter block
  1452.         
  1453.     Output Parameters:
  1454.         <none>
  1455.  
  1456.     Description:
  1457.         USB read requests complete here.
  1458.         We dequeue the MacOS DRVR read requests
  1459.  
  1460.     Change History:
  1461.         10 Aug 1998,    oja:        set readDrvr.ctl to NULL when finished
  1462.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1463.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1464.         20 Jul 1998,    oja:        retry transactions
  1465.          8 Jun 1998,    oja:        clear stalls on error
  1466.         28 Feb 1998,    oja:        Original version.
  1467. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1468. static void
  1469. ReadCompletion(USBPB *pb)
  1470. {
  1471.     //    call the user completion routine
  1472.     struct usbPrinterPBStruct
  1473.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1474.     IOParamPtr     clientParam = pPrinterPB->readDrvr.pb;
  1475.     OSStatus        err = pb->usbStatus;
  1476.     DCtlPtr            ctlLocal;
  1477.  
  1478. #if MACSBUG_ON_READ_COMPLETE
  1479.     Str255    text;
  1480.     sprintf( (char *)text, " PrinterClass Read Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1481.     text[0] = cstrlen((char *)text); // c2pstr
  1482.     DebugStr( text );
  1483. #endif
  1484.  
  1485. #if DOUBLE_BUFFER
  1486.     //
  1487.     //    copy the user data from our page aligned buffer
  1488.     //
  1489.     if ( pb->usbActCount > 0 )
  1490.         BlockCopy( pPrinterPB->pageReadAlignedBuffer, clientParam->ioBuffer + clientParam->ioActCount, pb->usbActCount );
  1491. #endif
  1492.     //    update the amount of data actually transferred
  1493.     clientParam->ioActCount += pb->usbActCount;
  1494.  
  1495.     switch( pb->usbStatus )
  1496.     {
  1497.         //
  1498.         //    only retry low level hardware problems
  1499.         //        note: abort transactions will end up here as well
  1500.         //
  1501.     case kUSBLinkErr:
  1502.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1503.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1504.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1505.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1506.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1507.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1508.         if (  --(pPrinterPB->readRetryCount) > 0 ) 
  1509.         {
  1510.             // we got an error, and we still want to retry, clear any stalls
  1511.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion retry" , pb->usbStatus );
  1512.             USBClearPipeStallByReference(pPrinterPB->readPipe);
  1513.             pb->usbStatus = noErr;
  1514.         }
  1515.         break;
  1516.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1517.         USBClearPipeStallByReference(pPrinterPB->readPipe);
  1518.         USBClearPipeStallByReference(pPrinterPB->device);
  1519.         break;
  1520.         //
  1521.         //    any other error will be reported to the client
  1522.         //
  1523.     default:
  1524.     case noErr:
  1525.         break;
  1526.     }
  1527.     if ( pb->usbStatus == noErr &&                                     // there were no problems
  1528.         pb->usbActCount >= pb->usbReqCount &&                        // we got all the data we requested
  1529.         clientParam->ioActCount < clientParam->ioReqCount )    // we still want more data
  1530.     {
  1531.         //
  1532.         //    haven't finish the client's request
  1533.         //        update the pointers and start another bulk read transaction
  1534.         //
  1535. #if LOCK_MEMORY
  1536.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1537.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion UnlockMem failed" ) );
  1538. #endif
  1539.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1540.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1541. #if MAX_USB_TRANSFER_SIZE
  1542.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1543.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1544. #endif
  1545. #if DOUBLE_BUFFER
  1546.         //
  1547.         //    make sure we have enough room in our buffer
  1548.         //
  1549.         if ( pb->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1550.             pb->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1551.         pb->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1552. #endif
  1553. #if LOCK_MEMORY
  1554.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1555.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion LockMem failed" ) );
  1556.         if ( err == noErr )
  1557. #endif
  1558.             err = USBBulkRead( pb );
  1559.         if ( immediateError(err) )
  1560.         {
  1561.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion finish immed err" , err );
  1562.  
  1563.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1564.             if ( pPrinterPB->readDrvr.ctl != NULL )
  1565.             {
  1566.                 ctlLocal = pPrinterPB->readDrvr.ctl;
  1567.                 pPrinterPB->readDrvr.ctl = NULL;
  1568.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1569.             }
  1570.         }
  1571.     }
  1572.     else
  1573.     {
  1574.         //
  1575.         //        either we have an error which we're not retrying
  1576.         //            or we successfully completed
  1577.         //
  1578. #if LOCK_MEMORY
  1579.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1580.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass ReadCompletion concluded UnlockMem failed" ) );
  1581. #endif
  1582.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "ReadCompletion Error" , pb->usbStatus ) );
  1583.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1584.         if ( pPrinterPB->readDrvr.ctl != NULL )
  1585.         {
  1586.             ctlLocal = pPrinterPB->readDrvr.ctl;
  1587.             pPrinterPB->readDrvr.ctl = NULL;
  1588.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal); 
  1589.         }
  1590.         else
  1591.         {
  1592.             IF_DEBUG( DebugStr( "\pReadCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
  1593.         }
  1594.     }
  1595. }
  1596.  
  1597.  
  1598. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1599.     Name:        WriteCompletion
  1600.  
  1601.     Input Parameters:    
  1602.         pb                        USB parameter block
  1603.         
  1604.     Output Parameters:
  1605.         <none>
  1606.  
  1607.     Description:
  1608.         USB write requests complete here.
  1609.         We dequeue the MacOS DRVR write requests
  1610.  
  1611.         when breaking up transactions we use ioActCount to determine how much remains 
  1612.                 of the original request and where the next request begins
  1613.         if we've failed with a USB error
  1614.             usbActCount indicates how much data has been transferred with the current request
  1615.             and if the retry count hasn't been exceeded
  1616.                 we proceed as if we'd just requested that much in this transactions
  1617.         note the retry count is cumulative for the original client request
  1618.             not for each usb transaction
  1619.  
  1620.     Change History:
  1621.         16 Nov 1998,    oja:        restored missing writeDrvr.ctl != NULL
  1622.          4 Nov 1998,    oja:        allow chaining of DRVR calls
  1623.         10 Aug 1998,    oja:        set writeDrvr.ctl to NULL when finished
  1624.         28 Jul 1998,    oja:        breakdown transactions into MAX_USB_TRANSFER_SIZE
  1625.         27 Jul 1998,    oja:        lock memory (UIM doesn't do this properly)
  1626.         20 Jul 1998,    oja:        retry transactions
  1627.         16 Jul 1998,    oja:        clear write pipe, not control pipe
  1628.         28 Feb 1998,    oja:        Original version.
  1629. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1630. static void
  1631. WriteCompletion(USBPB *pb)
  1632. {
  1633.     //    call the user completion routine
  1634.     struct usbPrinterPBStruct
  1635.                     *pPrinterPB =  (struct usbPrinterPBStruct    *) pb->usbRefcon;
  1636.     IOParamPtr     clientParam = pPrinterPB->writeDrvr.pb;
  1637.     DCtlPtr            ctlLocal;
  1638.     OSStatus        err = pb->usbStatus;
  1639.  
  1640. #if MACSBUG_ON_WRITE_COMPLETE
  1641.     Str255    text;
  1642.     sprintf( (char *)text, " PrinterClass Write Complete(%d): %d", pb->usbStatus, pb->usbActCount );
  1643.     text[0] = cstrlen((char *)text); // c2pstr
  1644.     DebugStr( text );
  1645. #endif
  1646.  
  1647.     //    update the amount of data actually transferred
  1648.     clientParam->ioActCount += pb->usbActCount;
  1649.  
  1650.     switch( pb->usbStatus )
  1651.     {
  1652.         //
  1653.         //    only retry low level hardware problems
  1654.         //        note: abort transactions will end up here as well
  1655.         //
  1656.     case kUSBLinkErr:
  1657.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  1658.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  1659.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  1660.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  1661.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  1662.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  1663.         if (  --(pPrinterPB->writeRetryCount) > 0 ) 
  1664.         {
  1665.             // we got an error, and we still want to retry, clear any stalls
  1666.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion retry" , pb->usbStatus );
  1667.             USBClearPipeStallByReference(pPrinterPB->writePipe);
  1668.             pb->usbStatus = noErr;
  1669.         }
  1670.         break;
  1671.     case kUSBAbortedError:                        /* user cancel, or hot unplug */
  1672.         USBClearPipeStallByReference(pPrinterPB->writePipe);
  1673.         USBClearPipeStallByReference(pPrinterPB->device);
  1674.         break;
  1675.         //
  1676.         //    any other error will be reported to the client
  1677.         //
  1678.     default:
  1679.     case noErr:
  1680.         break;
  1681.     }
  1682.  
  1683.     if ( pb->usbStatus == noErr && clientParam->ioActCount < clientParam->ioReqCount )
  1684.     {
  1685.         //
  1686.         //    haven't finish the client's request
  1687.         //        update the pointers and start another bulkOut transaction
  1688.         //
  1689. #if LOCK_MEMORY
  1690.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1691.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion UnlockMem failed" ) );
  1692. #endif
  1693.         pb->usbBuffer = clientParam->ioBuffer + clientParam->ioActCount;
  1694.         pb->usbReqCount = clientParam->ioReqCount - clientParam->ioActCount;
  1695. #if MAX_USB_TRANSFER_SIZE
  1696.         if ( pb->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1697.             pb->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1698. #endif
  1699. #if DOUBLE_BUFFER
  1700.         //
  1701.         //    make sure we have enough room in our buffer
  1702.         //    then copy the user data into our page aligned buffer
  1703.         //
  1704.         if ( pb->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1705.             pb->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1706.         BlockCopy( pb->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, pb->usbReqCount );
  1707.         pb->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1708. #endif
  1709. #if LOCK_MEMORY
  1710.         err = LockMemory( pb->usbBuffer, pb->usbReqCount );
  1711.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion LockMem failed" ) );
  1712.         if ( err == noErr )
  1713. #endif
  1714.             err = USBBulkWrite( pb );
  1715.         if ( immediateError(err) )
  1716.         {
  1717.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion finish immed err" , err );
  1718.  
  1719.             pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1720.             if ( pPrinterPB->writeDrvr.ctl != NULL )
  1721.             {
  1722.                 ctlLocal = pPrinterPB->writeDrvr.ctl;
  1723.                 pPrinterPB->writeDrvr.ctl = NULL;
  1724.                 CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, err, clientParam, ctlLocal ); 
  1725.             }
  1726.         }
  1727.     }
  1728.     else
  1729.     {
  1730.         //
  1731.         //        either we have an error which we're not retrying
  1732.         //            or we successfully completed
  1733.         //
  1734. #if LOCK_MEMORY
  1735.         err = UnlockMemory( pb->usbBuffer, pb->usbReqCount );
  1736.         IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass WriteCompletion concluded UnlockMem failed" ) );
  1737. #endif
  1738.         IF_DEBUG( if (pb->usbStatus != noErr) USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "WriteCompletion Error" , pb->usbStatus ) );
  1739.         pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  1740.         if ( pPrinterPB->writeDrvr.ctl != NULL )
  1741.         {
  1742.             ctlLocal = pPrinterPB->writeDrvr.ctl;
  1743.             pPrinterPB->writeDrvr.ctl = NULL;
  1744.             CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, ctlLocal ); 
  1745.         }
  1746.         else
  1747.         {
  1748.             IF_DEBUG( DebugStr( "\pWriteCompletion() pPrinterPB->readDrvr.ctl == NULL" ) );
  1749.         }
  1750.     }
  1751. }
  1752.  
  1753. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1754.     Name:        QueueRead
  1755.  
  1756.     Input Parameters:    
  1757.         pb                        MacOS device manager parameter block
  1758.         ctl                    device manager dCtl block
  1759.         pPrinterPB            current printing device class's storage
  1760.         
  1761.     Output Parameters:
  1762.         <none>
  1763.  
  1764.     Description:
  1765.         MacOS DRVR read requests are re-queued here to the USB
  1766.         Since we only allow one read request pending at a time, we're able
  1767.         to use the USB refCon to point to our class driver's storage.
  1768.  
  1769.     Change History:
  1770.         16 Nov 1998,    oja:        added LOCKMEMORY
  1771.         28 Feb 1998,    oja:        Original version.
  1772. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1773. void
  1774. QueueRead( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1775. {    
  1776.     OSStatus    err;
  1777.     USBPB        *usbprint = &pPrinterPB->in;
  1778.     
  1779. #if MACSBUG_ON_READ
  1780.     Str255    text;
  1781.  
  1782.     sprintf( (char *)text, " PrinterClass Read: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1783.     text[0] = cstrlen((char *)text); // c2pstr
  1784.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1785.     DebugStr( text );
  1786. #endif
  1787.  
  1788.     pb->ioActCount = 0;        // nothing transfered yet
  1789.     if ( pPrinterPB->terminating )
  1790.         pb->ioResult = abortErr;
  1791.     else
  1792.     {
  1793.  
  1794.         pPrinterPB->readRetryCount = 5;
  1795.         pPrinterPB->readDrvr.pb= pb;
  1796.         pPrinterPB->readDrvr.ctl = ctl;
  1797.         if ( pPrinterPB->readPipe != NULL )
  1798.         {
  1799.             SetNullUSBParamBlock( pPrinterPB->readPipe,  usbprint );
  1800.             usbprint->usbBuffer = pb->ioBuffer;
  1801.             usbprint->usbReqCount = pb->ioReqCount;
  1802.  
  1803. #if MAX_USB_TRANSFER_SIZE
  1804.             //
  1805.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1806.             //        or there is an error which can't be retried
  1807.             //
  1808.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1809.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1810. #endif
  1811. #if DOUBLE_BUFFER
  1812.             //
  1813.             //    make sure we have enough room in our buffer
  1814.             //    then copy the user data into our page aligned buffer
  1815.             //
  1816.             if ( usbprint->usbReqCount > pPrinterPB->pageReadAlignedBufferSize )
  1817.                 usbprint->usbReqCount = pPrinterPB->pageReadAlignedBufferSize;
  1818.             usbprint->usbBuffer = pPrinterPB->pageReadAlignedBuffer;
  1819. #endif
  1820.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1821.         
  1822.             usbprint->usbCompletion = (USBCompletion) ReadCompletion;
  1823.             
  1824.             pb->ioResult = ioInProgress;
  1825. #if LOCK_MEMORY
  1826.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1827.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueRead LockMem failed" ) );
  1828.             if ( err == noErr )
  1829. #endif
  1830.             err = USBBulkRead( usbprint );
  1831.             if ( immediateError(err) )
  1832.             {
  1833.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1834.                 pb->ioResult = err;
  1835.             }
  1836.         }
  1837.         else
  1838.         {
  1839.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Read to unopened pipe" , usbprint->usbStatus ) ;
  1840.             pb->ioResult = abortErr;
  1841.         }
  1842.     }
  1843. }
  1844.  
  1845. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1846.     Name:        QueueWrite
  1847.  
  1848.     Input Parameters:    
  1849.         pb                        MacOS device manager parameter block
  1850.         ctl                    device manager dCtl block
  1851.         pPrinterPB            current printing device class's storage
  1852.         
  1853.     Output Parameters:
  1854.         <none>
  1855.  
  1856.     Description:
  1857.         MacOS DRVR write requests are re-queued here to the USB
  1858.         Since we only allow one read request pending at a time, we're able
  1859.         to use the USB refCon to point to our class driver's storage.
  1860.  
  1861.     Change History:
  1862.         28 Feb 1998,    oja:        Original version.
  1863. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  1864. void
  1865. QueueWrite( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  1866. {
  1867.     OSStatus    err;
  1868.     USBPB        *usbprint = &pPrinterPB->out;
  1869. #if VIRTUAL_MEMORY_CHECK
  1870.     //
  1871.     //    dump the VM table
  1872.     //
  1873.     Str255                        text;
  1874.     LogicalToPhysicalTable    *vmTable;
  1875.     MemoryBlock                    *physical;
  1876.     unsigned long                vmCount,
  1877.                                     vmEntry,
  1878.                                     vmTblLength;
  1879. #endif
  1880.  
  1881. #if MACSBUG_ON_WRITE
  1882.     Str255    text;
  1883.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1884.     text[0] = cstrlen((char *)text); // c2pstr
  1885.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1886.     DebugStr( text );
  1887. #endif
  1888.  
  1889. #if VIRTUAL_MEMORY_CHECK
  1890.     //
  1891.     //    this check current won't compile without runtime error: need to lock memory, but lock has moved
  1892.     //
  1893.     sprintf( (char *)text, " PrinterClass Write: %d @ %08x", pb->ioReqCount, pb->ioBuffer );
  1894.     text[0] = cstrlen((char *)text); // c2pstr
  1895.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1896.     
  1897.     vmCount = 127;
  1898.     vmTblLength = (vmCount+1)*sizeof(MemoryBlock);
  1899.     vmTable = (LogicalToPhysicalTable *) NewPtrSys( vmTblLength );
  1900.     LockMemory( vmTable, vmTblLength );
  1901.     LockMemory( &vmCount, sizeof(unsigned long) );
  1902.     vmTable->logical.address = pb->ioBuffer;
  1903.     vmTable->logical.count = pb->ioReqCount;
  1904.     err = GetPhysical( vmTable, &vmCount );
  1905.     
  1906.     if ( err == noErr )
  1907.     {
  1908.         for ( vmEntry = 0, physical = &vmTable->physical[0]; vmEntry < vmCount; ++vmEntry , ++physical)
  1909.         {
  1910.             sprintf( (char *)text, " PrinterClass Write: VM @%08x (%d)", physical->address, physical->count );
  1911.             text[0] = cstrlen((char *)text); // c2pstr
  1912.             USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  1913.         }
  1914.     }
  1915.     UnlockMemory( vmTable, vmTblLength );
  1916.     UnlockMemory( &vmCount, sizeof(unsigned long) );
  1917. #endif
  1918.     pb->ioActCount = 0;        // nothing transfered yet
  1919.  
  1920.  
  1921.     usbprint->usbStatus = noErr;    // forget about abort and things from previous writes
  1922.     if ( pPrinterPB->terminating )
  1923.         pb->ioResult = abortErr;
  1924.     else
  1925.     {
  1926.         pPrinterPB->writeRetryCount = 5;
  1927.         pPrinterPB->writeDrvr.pb = pb;
  1928.         pPrinterPB->writeDrvr.ctl = ctl;
  1929.         if ( pPrinterPB->writePipe != NULL )
  1930.         {
  1931.             SetNullUSBParamBlock( pPrinterPB->writePipe,  usbprint );
  1932.             usbprint->usbBuffer = pb->ioBuffer;
  1933.             usbprint->usbReqCount = pb->ioReqCount;
  1934. #if MAX_USB_TRANSFER_SIZE
  1935.             //
  1936.             //    the completion routine will queue another BulkWrite until we exhaust the data
  1937.             //        or there is an error which can't be retried
  1938.             //
  1939.             if ( usbprint->usbReqCount > MAX_USB_TRANSFER_SIZE )
  1940.                 usbprint->usbReqCount = MAX_USB_TRANSFER_SIZE;
  1941. #endif
  1942. #if DOUBLE_BUFFER
  1943.             //
  1944.             //    make sure we have enough room in our buffer
  1945.             //    then copy the user data into our page aligned buffer
  1946.             //
  1947.             if ( usbprint->usbReqCount > pPrinterPB->pageWriteAlignedBufferSize )
  1948.                 usbprint->usbReqCount = pPrinterPB->pageWriteAlignedBufferSize;
  1949.             BlockCopy( usbprint->usbBuffer, pPrinterPB->pageWriteAlignedBuffer, usbprint->usbReqCount );
  1950.             usbprint->usbBuffer = pPrinterPB->pageWriteAlignedBuffer;
  1951. #endif
  1952.             usbprint->usbRefcon = (unsigned long) pPrinterPB;
  1953.         
  1954.             usbprint->usbCompletion = (USBCompletion) WriteCompletion;
  1955.              
  1956.             pb->ioResult = ioInProgress;
  1957.     
  1958. #if LOCK_MEMORY
  1959.             err = LockMemory( usbprint->usbBuffer, usbprint->usbReqCount );
  1960.             IF_DEBUG( if ( err != noErr ) DebugStr( "\pPrinterClass QueueWrite LockMem failed" ) );
  1961.             if ( err == noErr )
  1962. #endif
  1963.                 err = USBBulkWrite( usbprint );
  1964.             if ( immediateError(err) )
  1965.             {
  1966.                 IF_DEBUG( DebugStr( USBStatusStr(err, kPString) ) );
  1967.                 pb->ioResult = err;
  1968.             }
  1969.             //
  1970.             //    note our logging is one write for each the client request
  1971.             //        not one write for each usb transaction
  1972.             //
  1973.             LOGGING( fwrite( pb->ioBuffer, sizeof(char), pb->ioReqCount, logfile ) );
  1974.         }
  1975.         else
  1976.         {
  1977.             USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Write to unopened pipe" , usbprint->usbStatus );
  1978.             pb->ioResult = abortErr;
  1979.         }
  1980.     }
  1981. }
  1982.  
  1983.  
  1984. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1985.     Name:        Abort
  1986.  
  1987.     Input Parameters:    
  1988.         refNum            DRVR refnum
  1989.         pPrinterPB        current printing device class's storage
  1990.  
  1991.     Output Parameters:
  1992.         
  1993.     Description:
  1994.         Asynchronous completion.
  1995.         Note: USBAbortPipeByReference can leave the data toggle in the wrong state.
  1996.                 We need to abort both pipes, and then the client must soft reset the printer
  1997.                 to get the printer's data toggles correct.
  1998.         We prematurely call completion routines for active i/o so that CloseDriverSync
  1999.             will not hang the system after an abort, including hot unplug. This works out okay,
  2000.             since the request will be dequeued now, and when the i/o actually terminates
  2001.             the system will be called with an invalid queue element and then reject this second
  2002.             attempt to dequeue the i/o.
  2003.  
  2004.     Change History:
  2005.          4 Aug 1998,    oja:        abort both pipes, call completion routines
  2006.         28 Feb 1998,    oja:        Original version.
  2007. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2008. OSStatus
  2009. Abort( DriverRefNum refNum, struct usbPrinterPBStruct *pPrinterPB )
  2010. {
  2011.     OSStatus        err = noErr;
  2012.  
  2013.  
  2014.     refNum = 0;    // unused
  2015.     //
  2016.     //    if there's any pending io this will call the completion routine
  2017.     //
  2018.     err = USBAbortPipeByReference( pPrinterPB->writePipe );
  2019.     err = USBAbortPipeByReference( pPrinterPB->readPipe );
  2020.  
  2021.     if ( pPrinterPB->out.usbCompletion != (USBCompletion) NULL )
  2022.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->writeDrvr.pb, pPrinterPB->writeDrvr.ctl ); 
  2023.     if ( pPrinterPB->in.usbCompletion != (USBCompletion) NULL )
  2024.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, abortErr, pPrinterPB->readDrvr.pb, pPrinterPB->readDrvr.ctl ); 
  2025.     return err;
  2026. }
  2027.  
  2028.  
  2029. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2030.     Name:        CompletionProc
  2031.  
  2032.     Input Parameters:    
  2033.         pb                    USB param block ptr
  2034.     
  2035.     Output Parameters:
  2036.         
  2037.     Description:
  2038.         Asynchronous completion routine for DRVR requests.
  2039.  
  2040.     Change History:
  2041.         10 Aug 1998,    oja:        if error, do not set clientParam's ioResult
  2042.                                             explicitly (wait for JIODone)
  2043.         11 Jun 1998,    oja:        Original version.
  2044. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2045. static void 
  2046. CompletionProc(USBPB *pb)
  2047. {
  2048.     //    call the user completion routine
  2049.     struct usbPrinterPBStruct
  2050.                     *pPrinterPB = (struct usbPrinterPBStruct    *) pb->usbRefcon;
  2051.     IOParamPtr     clientParam = pPrinterPB->statusDrvr.pb;
  2052.  
  2053.     clientParam->ioActCount = pb->usbActCount;
  2054.  
  2055.     if ( pb->usbStatus != noErr ) 
  2056.     {
  2057.         USBClearPipeStallByReference(pb->usbReference);  // we got an error, try to clear any stalls
  2058.  
  2059.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "CompletionProc Error" , pb->usbStatus ) );
  2060.         IF_DEBUG( USBExpertStatus(pPrinterPB->device, USBStatusStr(pb->usbStatus, kPString) , pb->usbStatus ) );
  2061.     }
  2062.  
  2063.     pb->usbCompletion = (USBCompletion) NULL;    // checked by Finalize
  2064.     if ( pPrinterPB->statusDrvr.ctl != NULL )
  2065.         CallUniversalProc( LMGetJIODone(), uppIODoneProcInfo, pb->usbStatus, clientParam, pPrinterPB->statusDrvr.ctl ); 
  2066. }
  2067.  
  2068. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2069.     Name:        CentronicsStatus
  2070.  
  2071.     Input Parameters:    
  2072.         pb                        MacOS device manager parameter block
  2073.         ctl                    device manager dCtl block
  2074.         pPrinterPB            current printing device class's storage
  2075.  
  2076.     Output Parameters:
  2077.         pStatusByte        
  2078.         
  2079.     Description:
  2080.         setup the device request for a USB printer class request one byte status.
  2081.  
  2082.     Change History:
  2083.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2084.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2085.         11 Jun 1998,    oja:        Original version.
  2086. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2087. static void
  2088. CentronicsStatus( USBPB *usbprint, Ptr buffer, short interfaceNumber )
  2089. {
  2090.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2091.  
  2092.     usbprint->usb.cntl.BRequest = kUSBPrintClassGetCentronicsStatus;
  2093.     usbprint->usb.cntl.WValue = 0;
  2094.     usbprint->usb.cntl.WIndex = interfaceNumber;
  2095.  
  2096.     usbprint->usbReqCount = 1;
  2097.     usbprint->usbBuffer = buffer;
  2098. }
  2099.  
  2100. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2101.     Name:        SoftReset
  2102.  
  2103.     Input Parameters:    
  2104.         usbprint                USB param block
  2105.         interfaceNumber
  2106.  
  2107.     Output Parameters:
  2108.         
  2109.     Description:
  2110.         Setup the device request for a USB printer class request soft reset.
  2111.  
  2112.     Change History:
  2113.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2114.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2115.         11 Jun 1998,    oja:        Original version.
  2116. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2117. void
  2118. SoftReset( USBPB *usbprint, short interfaceNumber )
  2119. {
  2120.     usbprint->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBOut, kUSBClass, kUSBOther);
  2121.  
  2122.     usbprint->usb.cntl.BRequest = kUSBPrintClassSoftReset;
  2123.     usbprint->usb.cntl.WValue = 0;
  2124.     usbprint->usb.cntl.WIndex = interfaceNumber;
  2125.  
  2126.     usbprint->usbReqCount = 0;
  2127.     usbprint->usbBuffer = NULL;
  2128.  
  2129. }
  2130.  
  2131. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2132.     Name:        CapabilityRequest
  2133.  
  2134.     Input Parameters:    
  2135.         usbprint            USB parameter block
  2136.         p                    result pointer
  2137.         length            amount of data allocated
  2138.         config
  2139.         interfaceNum
  2140.         alternateSetting
  2141.         
  2142.  
  2143.     Output Parameters:
  2144.         p                    result pointer
  2145.         length            amount of data allocated
  2146.         
  2147.     Description:
  2148.         setup the device request for a USB printer class request 1284 id string.
  2149.  
  2150.     Change History:
  2151.         29 Jun 1998,    oja:        called from StatusControlRequests, change params
  2152.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2153.         11 Jun 1998,    oja:        Original version.
  2154. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2155. void
  2156. CapabilityRequest( USBPB *pb, Ptr p, long length, short configValue, short interfaceNumber, short alternateSetting  )
  2157. {
  2158.  
  2159.     pb->usb.cntl.BMRequestType = USBMakeBMRequestType(kUSBIn, kUSBClass, kUSBInterface);
  2160.  
  2161.     pb->usb.cntl.BRequest = kUSBPrintClassGetDeviceID;
  2162.     pb->usb.cntl.WValue = configValue;        // configuration
  2163.     pb->usb.cntl.WIndex = (interfaceNumber<<8) | alternateSetting;
  2164.  
  2165.     pb->usbReqCount = length;
  2166.     pb->usbBuffer = p;
  2167.  
  2168. }
  2169.  
  2170. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2171.     Name:        StatusControlRequests
  2172.  
  2173.     Input Parameters:    
  2174.         pb                        MacOS device manager parameter block
  2175.         ctl                    device manager dCtl block
  2176.         pPrinterPB            current printing device class's storage
  2177.  
  2178.     Output Parameters:
  2179.         
  2180.     Description:
  2181.         Asynchronous completion.
  2182.  
  2183.     Change History:
  2184.         26 Jun 1998,    oja:        changed params to be consistent w/ Read & Write
  2185.         11 Jun 1998,    oja:        Original version.
  2186. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2187.  
  2188. void
  2189. ControlStatusRequests( IOParamPtr pb, DCtlPtr ctl, struct usbPrinterPBStruct *pPrinterPB )
  2190. {
  2191.  
  2192.     //
  2193.     //    queue a transaction to retrieve the centronics status
  2194.     //
  2195.     OSStatus        err;
  2196.     USBPB            *usbprint = &pPrinterPB->pb;
  2197.     Boolean        dosomething = false;
  2198.     
  2199. #if DEBUG
  2200.     Str255        text;
  2201.  
  2202.     sprintf( (char *)text, " PrinterClass ControlStatus: %d", ((CntrlParam *) pb)->csCode );
  2203.     text[0] = cstrlen((char *)text); // c2pstr
  2204.     USBExpertStatus(pPrinterPB->device, text, usbprint->usbStatus );
  2205. #endif
  2206.  
  2207.     switch( ((CntrlParam *) pb)->csCode )
  2208.     {
  2209.     case kDrvrCentronicsStatus:
  2210.         dosomething = true;
  2211.         CentronicsStatus( usbprint,  *((Ptr *)((CntrlParam *) pb)->csParam), (pPrinterPB->interface)->interfaceNumber );
  2212.         break;
  2213.     case kDrvr1284IdString:
  2214.         dosomething = true;
  2215.         CapabilityRequest( usbprint,
  2216.                                 *((Ptr *)((CntrlParam *) pb)->csParam),
  2217.                                 *((long *) &((CntrlParam *) pb)->csParam[4]),
  2218.                                 (pPrinterPB->config)->configValue,        // configuration
  2219.                                 (pPrinterPB->interface)->interfaceNumber,
  2220.                                 (pPrinterPB->interface)->alternateSetting );
  2221.         break;
  2222.     case kDrvrSoftReset:
  2223.         dosomething = true;
  2224.         SoftReset( usbprint, (pPrinterPB->interface)->interfaceNumber );
  2225.         break;
  2226.     default:
  2227.         break;
  2228.     }
  2229.  
  2230.     if ( !dosomething )
  2231.         pb->ioResult = paramErr;
  2232.     else
  2233.     {
  2234.         SetNullUSBParamBlock(pPrinterPB->device,  usbprint );
  2235.         usbprint->usbCompletion = (USBCompletion)CompletionProc;
  2236.         usbprint->usbRefcon = (unsigned long) pPrinterPB;
  2237.     
  2238.         pb->ioResult = ioInProgress;
  2239.         pPrinterPB->statusDrvr.pb = pb;
  2240.         pPrinterPB->statusDrvr.ctl = ctl;
  2241.     
  2242.         err = USBDeviceRequest(usbprint);
  2243.         if(immediateError(err))
  2244.         {
  2245.             USBExpertFatalError(usbprint->usbReference, err, "\p" kStrPrinterClass "StatusControlRequests", 0);
  2246.             pb->ioResult = err;
  2247.         }
  2248.     }
  2249. }
  2250.  
  2251.  
  2252. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2253.     Name:        PrinterDeviceCompletionProc
  2254.  
  2255.     Input Parameters:    
  2256.         pb                refCon tells which state we're completing
  2257.  
  2258.     Output Parameters:
  2259.         <none>
  2260.         
  2261.     Description:
  2262.         Complete asynch transactions initiated by PrinterDeviceInitiateTransaction.
  2263.  
  2264.     Change History:
  2265.         17 Aug 1998,    oja:        don't retry high level errors (support hot unplug of root hub)
  2266.         20 Jul 1998,    oja:        clear pipe stall before retrying
  2267.         15 May 1998,    oja:        added missing break for GetCapabilityString
  2268.                                         reworked GetFullConfiguration to properly handle case
  2269.                                             where there's only one interface
  2270.         26 Mar 1998,    oja:        set info 1 to DEBUG StateStr
  2271.                                         (distinguishes completion from initiate)
  2272.         28 Feb 1998,    oja:        Original version.
  2273. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2274.  
  2275. static void 
  2276. PrinterDeviceCompletionProc(USBPB *pb)
  2277. {
  2278.     register struct usbPrinterPBStruct *pPrinterPB;
  2279.     int                                            numInterface;
  2280.  
  2281.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2282.     pPrinterPB->transDepth--; 
  2283.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2284.     {
  2285.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "CompletionProc Illegal Transaction Depth", pPrinterPB->transDepth );
  2286.     }
  2287.  
  2288.     IF_DEBUG( USBExpertStatus(pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString) , 1 ) );
  2289.  
  2290.     switch( pPrinterPB->pb.usbStatus )
  2291.     {
  2292.     case kUSBPending:
  2293.     case noErr:
  2294.         pPrinterPB->pb.usbRefcon &= ~kRetryTransaction;
  2295.         pPrinterPB->retryCount = kPrinterRetryCount;
  2296.         break;
  2297.     case kUSBLinkErr:
  2298.     case kUSBCRCErr:                                /*  Pipe stall, bad CRC */
  2299.     case kUSBBitstufErr:                            /*  Pipe stall, bitstuffing */
  2300.     case kUSBDataToggleErr:                        /*  Pipe stall, Bad data toggle */
  2301.     case kUSBNotRespondingErr:                    /*  Pipe stall, No device, device hung */
  2302.     case kUSBPIDCheckErr:                        /*  Pipe stall, PID CRC error */
  2303.     case kUSBWrongPIDErr:                        /*  Pipe stall, Bad or wrong PID */
  2304.     
  2305.         USBClearPipeStallByReference(pPrinterPB->device);  // we got an error, try to clear any stalls
  2306.         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "    retry", pPrinterPB->pb.usbStatus);
  2307.  
  2308.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  2309.         pPrinterPB->pb.usbRefcon |= kRetryTransaction;
  2310.         pPrinterPB->retryCount--;
  2311.         if (!pPrinterPB->retryCount)
  2312.         {
  2313.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Retry failed", pPrinterPB->pb.usbRefcon & ~kRetryTransaction);
  2314.             pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2315.             return;
  2316.         } else {
  2317.             pPrinterPB->pb.usbStatus = noErr; // let's retry one more time
  2318.         }
  2319.         break;
  2320.     default:
  2321.         //    don't retry
  2322.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2323.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2324.         break;
  2325.     }
  2326.  
  2327.     if (pPrinterPB->pb.usbRefcon & kTransactionPending)             
  2328.     {            
  2329.         int    length;
  2330.     
  2331.         //
  2332.         //    advance to the next state
  2333.         //
  2334.         pPrinterPB->pb.usbRefcon &= ~(kTransactionPending + kAsyncTransaction + kReturnFromDriver);
  2335.         switch(pPrinterPB->pb.usbRefcon)
  2336.         {
  2337.             case kGetConfigurationDescriptor:
  2338.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2339.                 {
  2340.                     pPrinterPB->pb.usbRefcon = kGetFullConfiguration;    
  2341.                 }
  2342.                 break;
  2343.                 
  2344.             case kGetFullConfiguration:
  2345.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2346.                 {
  2347.                     pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolBidirectional );
  2348.                     if ( pPrinterPB->interface == NULL )
  2349.                     {
  2350.                         pPrinterPB->interface = FindInterface( pPrinterPB->config, kUSBPrintClassProtocolUnidirectional );
  2351.                         if ( pPrinterPB->interface == NULL )
  2352.                             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't find protocol", 0);
  2353.                     }
  2354.                     if ( pPrinterPB->interface != NULL )
  2355.                         pPrinterPB->interfaceOffset =  (char *) pPrinterPB->interface - (char *) pPrinterPB->config;
  2356.  
  2357.                     //
  2358.                     // if there's only one interface (or alternate) supported
  2359.                     //        skip the attempt to assign the interface
  2360.                     //
  2361.                     numInterface = CountInterface( pPrinterPB->config, kUSBPrintClass, kUSBPrintSubClass );
  2362.                     if ( numInterface <= 1 )
  2363.                         pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2364.                     else
  2365.                         pPrinterPB->pb.usbRefcon = kSetInterface;
  2366.                 }
  2367.                 break;
  2368.                 
  2369.             case kSetInterface:
  2370.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2371.                 {
  2372.                     SetNullUSBParamBlock(pPrinterPB->device,  pb );
  2373.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2374.                 }
  2375.                 break;
  2376.                 
  2377.             case kGetCapabilityString:
  2378.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2379.                 {
  2380.                     //
  2381.                     //    In the short term (fall '98) several vendors are planning on shipping 
  2382.                     //        devices with a parallel port and using the Lucent USS-720 USB-to-parallel hardware.
  2383.                     //    Unfortunately this isn't an ideal solution from the USB perspective:
  2384.                     //        users can leave the printer off while the cable responds that there's
  2385.                     //        a printer connected. Then we have no way of using the DEVICE_ID
  2386.                     //        string to tag the printer and register it.
  2387.                     //    To alleviate this situation, we repeatedly poll the USS-720 if the DEVICE_ID
  2388.                     //        string is null. Every few seconds we'll retry this state.
  2389.                     //    At some point the user wants to print and switches on the printer. The class
  2390.                     //    driver then picks up from here and registers the device properly.
  2391.                     //
  2392.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  2393.                     if ( IsLucentCable( &pPrinterPB->desc ) && pPrinterPB->pb.usbActCount == 0 )
  2394.                         pPrinterPB->pb.usbRefcon = kDelayGetCapability;
  2395.                     else
  2396.                         pPrinterPB->pb.usbRefcon = kGetInterface;
  2397.                 }
  2398.                 else if ( pPrinterPB->pb.usbStatus == kUSBOverRunErr )
  2399.                 {
  2400.                     //
  2401.                     //    if we've haven't managed to read the whole capability string
  2402.                     //        we need to allocate memory and read it in by initiating kGetFullCapabilityString
  2403.                     //
  2404.                     length = pPrinterPB->capabilityString[1] | (pPrinterPB->capabilityString[0] << 8);
  2405.  
  2406.                     if ( length > sizeof(pPrinterPB->capability) &&
  2407.                             pPrinterPB->pb.usbRefcon == kGetCapabilityString )
  2408.                         pPrinterPB->pb.usbRefcon = kGetFullCapabilityString;
  2409.                 }
  2410.                 break;
  2411.             case kDelayGetCapability:
  2412.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2413.                     pPrinterPB->pb.usbRefcon = kGetCapabilityString;
  2414.                 break;
  2415.             case kGetFullCapabilityString:
  2416.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2417.                     pPrinterPB->pb.usbRefcon = kGetInterface;
  2418.                 break;
  2419.             case kGetInterface:
  2420.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2421.                     pPrinterPB->pb.usbRefcon = kOpenBulkOutPipe;
  2422.                 break;
  2423.             case kOpenBulkOutPipe:
  2424.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2425.                 {
  2426.                     pPrinterPB->writePipe = pPrinterPB->pb.usbReference; // remember the ref
  2427.                     pPrinterPB->out = pPrinterPB->pb;
  2428.                     pPrinterPB->out.usbCompletion =  (USBCompletion) NULL;    // for finalize
  2429.  
  2430.                     if ( pPrinterPB->interface->interfaceProtocol == kUSBPrintClassProtocolBidirectional )
  2431.                         pPrinterPB->pb.usbRefcon = kOpenBulkInPipe;
  2432.                     else
  2433.                         pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  2434.                 }
  2435.                 break;
  2436.             case kOpenBulkInPipe:
  2437.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2438.                 {
  2439.                     pPrinterPB->readPipe = pPrinterPB->pb.usbReference;
  2440.                     pPrinterPB->in = pPrinterPB->pb;
  2441.                     pPrinterPB->in.usbCompletion =  (USBCompletion) NULL;    // for finalize
  2442.  
  2443.                     pPrinterPB->pb.usbRefcon = kEnterNameRegistry;
  2444.                 }
  2445.                 break;
  2446.             case kEnterNameRegistry:
  2447.                 //
  2448.                 //    note: this state isn't reachable
  2449.                 //
  2450.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2451.                 {
  2452.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2453.                 }
  2454.                 break;
  2455.             case kGetCentronicsStatus:
  2456.                 //
  2457.                 //    if InitiateTransaction fell through on it's kEnterNameRegistry case we'll end up here
  2458.                 //
  2459.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2460.                 {
  2461. #if DEBUG
  2462.                     Str255    text, te;
  2463.                     hexstr( sizeof(char), &pPrinterPB->centronics.b, (char *) te );
  2464.                     sprintf( (char *)text, " PrinterClass Status: %s", te );
  2465.                     text[0] = cstrlen((char *)text); // c2pstr
  2466.                     USBExpertStatus(pPrinterPB->device, text, pb->usbStatus );
  2467. #endif
  2468. #if DEBUG
  2469.                     if ( !pPrinterPB->centronics.status.notError )
  2470.                     {
  2471.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Error at printer", pPrinterPB->pb.usbStatus);
  2472.                     }
  2473.                     if ( pPrinterPB->centronics.status.paperError )
  2474.                     {
  2475.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "Check paper", pPrinterPB->pb.usbStatus);
  2476.                     }
  2477.                     if ( !pPrinterPB->centronics.status.select )
  2478.                     {
  2479.                         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "printer offline", pPrinterPB->pb.usbStatus);
  2480.                     }
  2481. #endif
  2482.                     pPrinterPB->pb.usbRefcon = kDelayGetCentronicsStatus;
  2483.                 }
  2484.                 break;
  2485.             case kDelayGetCentronicsStatus:
  2486.                 //
  2487.                 //    loop around continually getting status
  2488.                 //
  2489.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2490.                 {
  2491.                     pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2492.                 }
  2493.                 break;
  2494.             case kNilCompletion:
  2495.             default:
  2496.                 if ( pPrinterPB->pb.usbStatus == noErr )
  2497.                     pPrinterPB->pb.usbRefcon = kUndefined | kReturnFromDriver;
  2498.                 break;
  2499.         }
  2500.     }
  2501.  
  2502.     if ( pPrinterPB->terminating )
  2503.     {
  2504.         //    if we've been hot unplugged
  2505.         //        don't startup any new transactions
  2506.         //     allow PrintDriverFinalize to continue
  2507.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2508.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2509.     }
  2510.     else if ( pPrinterPB->pb.usbStatus == noErr )
  2511.     {
  2512.         if (!(pPrinterPB->pb.usbRefcon & kReturnFromDriver))
  2513.             PrinterDeviceInitiateTransaction(pb);
  2514.     }
  2515.     else
  2516.     {
  2517.         pPrinterPB->pb.usbCompletion    = (USBCompletion) NULL;
  2518.         pPrinterPB->pb.usbRefcon = kReturnFromDriver;
  2519.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, StateStr(pPrinterPB->pb.usbRefcon, kPString), pPrinterPB->pb.usbRefcon);
  2520.         USBExpertFatalError(pPrinterPB->device, pPrinterPB->pb.usbStatus, USBStatusStr(pPrinterPB->pb.usbStatus, kPString), 0);
  2521.     }
  2522. }
  2523.  
  2524. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2525.     Name:        PrinterDeviceInitiateTransaction
  2526.  
  2527.     Input Parameters:    
  2528.         pb            USB parameter block
  2529.         
  2530.     Output Parameters:
  2531.         
  2532.     Description:
  2533.         Since USB transactions are asynchronous we use the refCon field
  2534.         in the parameter block to implement the following logic via a state machine.
  2535.  
  2536.         Start out by getting the device configuration descriptor
  2537.         If the device has more than one printing interface
  2538.             If a bidirectional interface exists
  2539.                 select it
  2540.             Else
  2541.                 select the (mandatory) unidirectional interface
  2542.         Get the (manadatory) 1284 capability string
  2543.         Open pipes to the BulkOut (and optional BulkIn) endpoints
  2544.         Install read and write drivers in the unit table
  2545.         Using information from the capability string
  2546.             enter the printer in the MacOS name registry.
  2547.         
  2548.  
  2549.     Change History:
  2550.         15 May 1998,    oja:        cleanup error/status messages
  2551.                                         handle setinterface correctly if only one
  2552.                                             interface is available
  2553.         28 Feb 1998,    oja:        Original version.
  2554. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2555. void
  2556. PrinterDeviceInitiateTransaction(USBPB *pb)
  2557. {
  2558.     register struct usbPrinterPBStruct    *pPrinterPB;
  2559.     int                                            length;
  2560.     OSStatus                                        err;
  2561.  
  2562.     pPrinterPB = (struct usbPrinterPBStruct *)(pb);
  2563.     pPrinterPB->transDepth++;
  2564.     if ((pPrinterPB->transDepth < 0) || (pPrinterPB->transDepth > 1))
  2565.     {
  2566.         USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction illegal transaction depth", 0);
  2567.     }
  2568.     IF_DEBUG( USBExpertStatus( pPrinterPB->device, StateStr(pPrinterPB->pb.usbRefcon, kPString), 0) );     
  2569.  
  2570.     switch(pPrinterPB->pb.usbRefcon & ~kRetryTransaction)
  2571.     {
  2572.         case kGetConfigurationDescriptor:
  2573.             //
  2574.             //    find the device's configuration information
  2575.             //
  2576.             pPrinterPB->config = (USBConfigurationDescriptorPtr) pPrinterPB->configuration;
  2577.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, sizeof(USBConfigurationDescriptor) );
  2578.             break;
  2579.             
  2580.         case kGetFullConfiguration:
  2581.             //
  2582.             //    not enough room in statically allocated memory for device's configuration
  2583.             //    try again after allocating enough memory
  2584.             //        (memory is released on finalize)
  2585.             length = USBToHostWord( (pPrinterPB->config)->totalLength );
  2586.  
  2587.             pPrinterPB->config = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2588.             GetConfigurationDescriptor( &pPrinterPB->pb, pPrinterPB->config, length );
  2589.             break;
  2590.         case kSetInterface:
  2591.             //
  2592.             //    having identified the configuration
  2593.             //        set the device to our prefered interface
  2594.             //
  2595.             SetInterface( &pPrinterPB->pb, pPrinterPB->interface->interfaceNumber, pPrinterPB->interface->alternateSetting );
  2596.             break;
  2597.         case kGetCapabilityString:
  2598.             //
  2599.             //    once the interface (and alternate) is assinged
  2600.             //        we can retreive the 1284 capability string to see what kind of printer
  2601.             //        is attached
  2602.             pPrinterPB->capabilityString = pPrinterPB->capability;
  2603.             GetCapability( pPrinterPB, pPrinterPB->capabilityString, sizeof(pPrinterPB->capability) );
  2604.             break;
  2605.         case kDelayGetCapability:
  2606.             //
  2607.             //    USS-720 USB-parallel cable: couldn't get the capability string because the printer is off
  2608.             //        Delay a few seconds and try again.
  2609.             //        Will succeed when the user turns the printer on.
  2610.             //
  2611.             pPrinterPB->pb.usbReqCount = kUSS720MillisecondDelay;
  2612.             pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
  2613.             err = USBDelay(&pPrinterPB->pb);
  2614.             if(immediateError(err))
  2615.             {
  2616.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCapability", 0);
  2617.             }
  2618.             break;
  2619.         case kGetFullCapabilityString:
  2620.             //
  2621.             // the capability string was too long to fit in the statically allocated space
  2622.             // need to release this memory when we finalize our driver
  2623.             //
  2624.             length = pPrinterPB->capability[1] | (pPrinterPB->capability[0]<<8);
  2625.  
  2626.             pPrinterPB->capabilityString = MemAllocatePhysicallyContiguous ((ByteCount)length, true);
  2627.             if ( pPrinterPB->capabilityString )
  2628.                 GetCapability( pPrinterPB, pPrinterPB->capabilityString, length );
  2629.             else
  2630.                 USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "Can't allocate capability", 0);
  2631.             break;
  2632.         case kGetInterface:
  2633.             // failsafe check that we've got the right setup
  2634.             //    it's possible the device didn't respond to our SetInterface
  2635.             GetInterface( &pPrinterPB->pb, &pPrinterPB->whichAltInterface );
  2636.             break;
  2637.         case kOpenBulkOutPipe:
  2638.             //
  2639.             //    open mandatory bulk out pipe
  2640.             //
  2641.             OpenBulkEndpoint( pPrinterPB, kOpenBulkOutPipe );
  2642.             break;
  2643.         case kOpenBulkInPipe:    
  2644.             //
  2645.             //    open optional bulk in pipe
  2646.             //
  2647.             OpenBulkEndpoint( pPrinterPB, kOpenBulkInPipe );
  2648.             break;
  2649.         case kEnterNameRegistry:
  2650.             //
  2651.             //    once we know what device we're dealing with
  2652.             //        open the i/o channel(s) to the device
  2653.             //        and enter it in the name registry
  2654.             //    modification by RRK - Use the Notification Manager to 
  2655.             //     make the call to InstallDrivers and RegisterDevice.
  2656.             //        The original sample code made the NameRegistry calls and the call
  2657.             //     to install the driver from a completion routine.
  2658.             //
  2659.             gNMRec.qType = nmType;
  2660.             gNMRec.nmMark = 0;        // no mark next to app name in application menu
  2661.             gNMRec.nmIcon = nil;        // no blinking icon in menu bar
  2662.             gNMRec.nmSound = nil;    // no sound associated with this nm request
  2663.             gNMRec.nmStr = nil;        // no alert box to be displayed
  2664.             gNMRec.nmResp = (NMUPP)CompleteDriverInit;
  2665.             gNMRec.nmRefCon = (long)pPrinterPB;
  2666.             
  2667.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;    // Finalize
  2668.             
  2669.             err = NMInstall(&gNMRec);
  2670. /*
  2671.             // the following is the original code for this sample.  These calls are now made from a 
  2672.             // Notification Manager routine.
  2673.             err = InstallDrivers( pPrinterPB );
  2674.             if ( err == noErr )
  2675.                 err = RegisterDevice( pPrinterPB );
  2676.             if ( err != noErr )
  2677.                 USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2678. */
  2679.  
  2680.             if (err != noErr)
  2681.                 USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "NMInstall failed", 0);
  2682.              // to stress test usb bus, fallthrough to kGetCentronicsStatus 
  2683.             break;
  2684.  
  2685.         case kGetCentronicsStatus:
  2686.             SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  2687.  
  2688.             CentronicsStatus( &pPrinterPB->pb,  &pPrinterPB->centronics.b, (pPrinterPB->interface)->interfaceNumber );
  2689.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2690.             pPrinterPB->pb.usbRefcon = kGetCentronicsStatus | kTransactionPending | kAsyncTransaction;
  2691.         
  2692.             err = USBDeviceRequest(&pPrinterPB->pb);
  2693.             if(immediateError(err))
  2694.             {
  2695.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kGetCentronicsStatus", 0);
  2696.             }
  2697.             break;
  2698.         case kDelayGetCentronicsStatus:
  2699.             SetNullUSBParamBlock( pPrinterPB->device, &pPrinterPB->pb );
  2700.  
  2701.             pPrinterPB->pb.usbReqCount = kUSS720StatusMSDelay;
  2702.             pPrinterPB->pb.usbCompletion = (USBCompletion)PrinterDeviceCompletionProc;
  2703.             pPrinterPB->pb.usbRefcon |= kTransactionPending | kAsyncTransaction;
  2704.  
  2705.             err = USBDelay(&pPrinterPB->pb);
  2706.             if(immediateError(err))
  2707.             {
  2708.                 USBExpertFatalError(pb->usbReference, err, "\p" kStrPrinterClass "kDelayGetCentronicsStatus", 0);
  2709.             }
  2710.             break;
  2711.         case kReturnFromDriver:
  2712.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2713.             break;
  2714.         default:
  2715.             USBExpertFatalError(pPrinterPB->device, kUSBInternalErr, "\p" kStrPrinterClass "InitiateTransaction unknown transaction", 0);
  2716.             pPrinterPB->pb.usbCompletion = (USBCompletion) NULL;
  2717.             pPrinterPB->pb.usbRefcon = kUndefined + kReturnFromDriver;
  2718.             break;
  2719.     }
  2720. }
  2721.  
  2722.  
  2723. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2724.     Name:        PrintDriverEntry
  2725.  
  2726.     Input Parameters:    
  2727.         
  2728.     Output Parameters:
  2729.         
  2730.     Description:
  2731.         This is where the system instantiates a USB printing device.
  2732.  
  2733.         We need to install drivers in the MacOS unitTable, and a reference
  2734.         in the name registry.
  2735.         
  2736.         But the information we need to do this is only available after some 
  2737.         USB transactions have completed. So we initiate here a series of asynchronous
  2738.         USB operations to get that information (by calling the first 
  2739.  
  2740.     Change History:
  2741.         31 Jul 1998,    oja:        page-aligned double buffer i/o
  2742.         30 Jun 1998,    oja:        change CentronicsStatus to ControlStatusRequests
  2743.         28 Feb 1998,    oja:        Original version.
  2744. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2745. void 
  2746. PrintDriverEntry(
  2747.     USBDeviceRef                    device,
  2748.     USBDeviceDescriptorPtr        desc,
  2749.     USBInterfaceDescriptorPtr    pInterface
  2750.     )
  2751. {
  2752.     static Boolean        beenThereDoneThat = false;
  2753.     OSStatus                err;
  2754.     RoutineDescriptor qw = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBWriteProcInfo, QueueWrite);
  2755.     RoutineDescriptor qr = BUILD_ROUTINE_DESCRIPTOR( uppQueueUSBReadProcInfo, QueueRead);
  2756.     RoutineDescriptor qa = BUILD_ROUTINE_DESCRIPTOR( uppAbortProcInfo, Abort);
  2757.     RoutineDescriptor qs = BUILD_ROUTINE_DESCRIPTOR( uppControlStatusProcInfo, ControlStatusRequests );
  2758.     
  2759.     if( !beenThereDoneThat)
  2760.     {
  2761.         beenThereDoneThat = true;
  2762.             
  2763.         printerClassRecord.desc = *desc;                /* keep a copy of the device descriptor */
  2764.         if ( pInterface != NULL )
  2765.             printerClassRecord.interface = pInterface;
  2766.     
  2767.         printerClassRecord.device = device;
  2768.         printerClassRecord.transDepth = 0;            /* init Delay Callback Depth */
  2769.     
  2770.         printerClassRecord.inRefNum =  -1;            /* initially no DRVRs added to UnitTable */
  2771.         printerClassRecord.outRefNum =  -1;    
  2772.         err = LoadResources( &printerClassRecord );
  2773.         if ( err != noErr )
  2774.             USBExpertFatalError( device, err, "\p" kStrPrinterClass "LoadResources failed", 0);
  2775.         //
  2776.         //    routines to write and read to the device must be called by 68K DRVR
  2777.         //        so we use mixed-mode manager to dispatch between PPC and 68K
  2778.         //
  2779.         printerClassRecord.qwrite = (QueueUSBWriteUPP) &printerClassRecord.qwriteRD;
  2780.         printerClassRecord.qwriteRD = qw;
  2781.     
  2782.         printerClassRecord.qread = (QueueUSBReadUPP) &printerClassRecord.qreadRD;
  2783.         printerClassRecord.qreadRD = qr;    
  2784.         
  2785.         printerClassRecord.qstatus = (ControlStatusUPP) &printerClassRecord.qstatusRD;
  2786.         printerClassRecord.qstatusRD = qs;
  2787.  
  2788.         printerClassRecord.qabort = (AbortUPP) &printerClassRecord.qabortRD;
  2789.         printerClassRecord.qabortRD = qa;
  2790.  
  2791.         printerClassRecord.r = (QueueUSBReadUPP) QueueRead;
  2792.         printerClassRecord.w = (QueueUSBWriteUPP) QueueWrite;
  2793.         printerClassRecord.s = (ControlStatusUPP) ControlStatusRequests;
  2794.         printerClassRecord.a = (AbortUPP) Abort;
  2795.  
  2796.         SetNullUSBParamBlock( device, &printerClassRecord.pb );
  2797.         SetNullUSBParamBlock( 0, &printerClassRecord.in );        // fill in pipe ref later
  2798.         SetNullUSBParamBlock( 0, &printerClassRecord.out );    // fill in pipe ref later
  2799.  
  2800. #if DOUBLE_BUFFER
  2801.         //
  2802.         // Assume 1. TRANSFER_SIZE is a power of 2
  2803.         //    Assume 2. malignedBuffer is allocated to be 3*TRANSFER_SIZE
  2804.         //
  2805.         printerClassRecord.pageWriteAlignedBufferSize = TRANSFER_SIZE;                            // should get this from VM
  2806.         printerClassRecord.pageWriteAlignedBuffer = printerClassRecord.malignedBuffer;
  2807.         // align it below the buffer, then bring it into the range of the buffer
  2808.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) &= ~(printerClassRecord.pageWriteAlignedBufferSize - 1);    //assumption1
  2809.         *((UInt32 *) &printerClassRecord.pageWriteAlignedBuffer) += printerClassRecord.pageWriteAlignedBufferSize;            //assumption2
  2810.  
  2811.         printerClassRecord.pageReadAlignedBufferSize = TRANSFER_SIZE;
  2812.         printerClassRecord.pageReadAlignedBuffer = printerClassRecord.pageWriteAlignedBuffer + TRANSFER_SIZE;
  2813. #endif
  2814.         printerClassRecord.terminating = 0;
  2815.     
  2816.         //
  2817.         //    Just to be thorough, lets hold our paramter blocks so that we won't page them at
  2818.         //        interrupt time. (We should be in the System heap and automatically held.)
  2819.         //
  2820.         HoldMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  2821.  
  2822.  
  2823.         //
  2824.         // Start out at first state
  2825.         //
  2826.         printerClassRecord.pb.usbRefcon = kGetConfigurationDescriptor;
  2827.         PrinterDeviceInitiateTransaction(&printerClassRecord.pb);
  2828.     }
  2829. }
  2830.  
  2831. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2832.     Name:        PrintDriverFinalize
  2833.  
  2834.     Input Parameters:    
  2835.         
  2836.     Output Parameters:
  2837.         
  2838.     Description:
  2839.         release any allocated storage
  2840.         remove DRVRs from the UnitTable
  2841.  
  2842.         One small complication happens when the USS-720 cable is used. It's possible
  2843.         that the user has the device plugged in, but the printer wasn't powered on.
  2844.         In this case, our state machine is still cycling between the states 
  2845.         kDelayGetCapability and kGetCapabilityString. If we terminate before the delay
  2846.         returns we'll crash the system. We monitor terminating to handle this
  2847.         
  2848.     Change History:
  2849.         17 Aug 1998,    oja:        don't deregister if the root hub was hot unplugged
  2850.         10 Aug 1998,    oja:        call Abort to cleanup pending read/write transactions
  2851.         31 Jul 1998,    oja:        cleanup some hotplugging problems
  2852.         12 Jul 1998,    oja:        allow for hot unplugging during initial startup
  2853.                                             wait for completion if refCon indicates some
  2854.                                             transaction is in progress
  2855.         24 Apr 1998,    oja:        added call to DeregisterDevice
  2856.         28 Feb 1998,    oja:        Original version.
  2857. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2858. OSStatus
  2859. PrintDriverFinalize( void )
  2860. {
  2861.     OSStatus            result = noErr;
  2862.     unsigned long    tc;
  2863.     //
  2864.     //    notify state machine not to continue
  2865.     //
  2866.     printerClassRecord.terminating = 1;
  2867.     LOGGING( fclose( logfile ) );
  2868.     //
  2869.     //    abort and wait for any pending read/write/status calls
  2870.     //
  2871.     if ( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL )
  2872.     {
  2873.         USBAbortPipeByReference( printerClassRecord.device );
  2874.     }
  2875.     Abort( 0, &printerClassRecord );
  2876.  
  2877.     //    wait for any outstanding startup transactions
  2878.     tc = TickCount() + 10*60;    // wait up to ten seconds
  2879.     while ( TickCount() < tc )
  2880.     {
  2881.         if ( printerClassRecord.pb.usbCompletion == (USBCompletion) NULL
  2882.                 && printerClassRecord.out.usbCompletion == (USBCompletion) NULL 
  2883.                 && printerClassRecord.in.usbCompletion == (USBCompletion) NULL )
  2884.             break;
  2885.     }
  2886.     if ( printerClassRecord.pb.usbCompletion != (USBCompletion) NULL
  2887.             || printerClassRecord.out.usbCompletion != (USBCompletion) NULL 
  2888.             || printerClassRecord.in.usbCompletion != (USBCompletion) NULL )
  2889.         result = (OSStatus) kUSBDeviceBusy;
  2890.  
  2891.     if ( printerClassRecord.pb.usbStatus == noErr )        // don't bother if there was a hot unplug of root hub
  2892.     {
  2893.         //
  2894.         //    remove printer from the name registry
  2895.         //
  2896.         DeregisterDevice( &printerClassRecord );
  2897.     }
  2898.     //
  2899.     //    release any allocated storage
  2900.     //
  2901.     if ( printerClassRecord.capabilityString != printerClassRecord.capability )
  2902.     {
  2903.         MemDeallocatePhysicallyContiguous( printerClassRecord.capabilityString );
  2904.         printerClassRecord.capabilityString = printerClassRecord.capability;
  2905.     }
  2906.  
  2907.     if ( (unsigned char *) printerClassRecord.config != printerClassRecord.configuration )
  2908.     {
  2909.         MemDeallocatePhysicallyContiguous( printerClassRecord.config );
  2910.     }
  2911.     //
  2912.     //    don't need to hang on to param blocks after we've gone away
  2913.     //
  2914.     UnholdMemory( &printerClassRecord, sizeof(struct usbPrinterPBStruct) );
  2915.  
  2916.     return result;
  2917. }
  2918.  
  2919. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2920.     Name:        CompleteDriverInit
  2921.  
  2922.     Input Parameters:    
  2923.         NMRecPtr             which is also a global variable
  2924.         
  2925.     Output Parameters:
  2926.         none
  2927.         
  2928.     Description:
  2929.         This routine is an addition by RRK to be passed to the Notification Manager
  2930.         to be called to install the driver and register entries in the Name Registry.
  2931.         
  2932.         These actions must be made at task time, however in the original source code
  2933.         they were made from a completion proc.
  2934.         
  2935. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2936. void CompleteDriverInit(NMRecPtr nmrecptr)
  2937. {
  2938.     OSErr                                err;
  2939.     struct usbPrinterPBStruct    *pPrinterPB;
  2940.     
  2941.         // remove the notification request from the queue
  2942.     NMRemove(nmrecptr);
  2943.     
  2944.     pPrinterPB = (struct usbPrinterPBStruct*) nmrecptr->nmRefCon;
  2945.     err = InstallDrivers( pPrinterPB );
  2946.     if (err == noErr)
  2947.         err = RegisterDevice( pPrinterPB );
  2948.     if ( err != noErr )
  2949.         USBExpertFatalError(pPrinterPB->device, err, "\p" kStrPrinterClass "RegisterDevice failed", 0);
  2950.     else
  2951.         USBExpertStatus(pPrinterPB->device, "\p" kStrPrinterClass "RegisterDevice worked", 0);
  2952.     
  2953.     // as per the comments from the PrinterDeviceInitiateTransaction call above case kEnterNameRegistry, 
  2954.     // if we want to stress test the usb bus  we can set the 
  2955.     // pPrinterPB->pb.usbRefcon field to kGetCentronicsStatus and call PrinterDeviceInitiateTransaction
  2956.     // as follows
  2957.     
  2958.     // pPrinterPB->pb.usbRefcon = kGetCentronicsStatus;
  2959.     //    PrinterDeviceInitiateTransaction((USBPB)pPrinterPB);
  2960. }
  2961.  
  2962. /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  2963.     Name:        CFMInitialization
  2964.  
  2965.     Input Parameters:    
  2966.         initBlock
  2967.         
  2968.     Output Parameters:
  2969.         printerClassDriverFileSpec        set global
  2970.         
  2971.     Description:
  2972.         We use the code fragment initialization to get our filespec which 
  2973.         LoadResources will use to open our resource fork.
  2974.         
  2975.         A peculiarity of the USB 1.0 implementation is that does not lock the
  2976.         driver into physical memory. As a result a driver which does not call
  2977.         SetDriverClosureMemory on it's fragment will likely be paged in during
  2978.         interrupt time and a double bus-fault will occur. The solution for this
  2979.         is to have the USB Expert call SetDriverClosureMemory in a future release
  2980.         of the USB stack. In the meantime, we call it on ourselves to lock us into
  2981.         physical memory. When the USB stack is revved, one call to SetDriverClosureMemory
  2982.         (either this one or the Expert's) will be treated as a NOP.
  2983.  
  2984.     Change History:
  2985.         31 Jul 1998,    oja:        added call to SetDriverClosureMemory
  2986.         11 Jun 1998,    oja:        Original version.
  2987. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  2988. OSErr
  2989. CFMInitialization( CFragInitBlock *initBlock )
  2990. {
  2991.     //
  2992.     //    get a reference to our file so that we can open up the resource fork later on
  2993.     //
  2994.     if ( CFragHasFileLocation( initBlock->fragLocator.where ) )
  2995.         printerClassDriverFileSpec = *(initBlock->fragLocator.u.onDisk.fileSpec);
  2996.  
  2997.     // don't page us, we're a device driver
  2998.     return SetDriverClosureMemory( (CFragConnectionID) initBlock->closureID, true );
  2999.  
  3000. }
  3001.  
  3002.  
  3003.  
  3004. // eof
  3005.